public void handleCommandEvent(Event obj, String cmd) {
    super.handleCommandEvent(obj, cmd);

    int equalsPos = cmd.indexOf("=");

    String command = (equalsPos < 0) ? cmd : cmd.substring(0, equalsPos);
    String value = (equalsPos < 0) ? "" : cmd.substring(equalsPos + 1);

    // Set IP address.
    if (command.toUpperCase().equals("IPADDR")) {
      _pjLink.setIPAddress(value);

      if (value.length() == 0) {
        System.out.println("PJLink IP address cleared for " + dvDuet.getDPS().toString() + ".");
      } else {
        System.out.println(
            "PJLink IP address set to "
                + _pjLink.getIPAddress()
                + " for "
                + dvDuet.getDPS().toString()
                + ".");
      }
    } else if (command.toUpperCase().equals("?LAMPTIME")) {
      _pjLink.queryLampHours();
    } else if (command.toUpperCase().equals("?CONN")) {
      System.out.println(
          "PJLink "
              + _pjLink.getIPAddress()
              + " connection status: "
              + !_pjLink.getConnectionError());
    } else if (command.toUpperCase().equals("DEBUG")) {
      if (value.equals("1") || value.toUpperCase().equals("TRUE")) {
        _pjLink.setPrintDebug(true);
        System.out.println("Debug enabled for device " + dvDuet.getDPS().toString() + ".");
      } else if (value.equals("0") || value.toUpperCase().equals("FALSE")) {
        _pjLink.setPrintDebug(false);
        System.out.println("Debug disabled for device " + dvDuet.getDPS().toString() + ".");
      }
    } else if (command.toUpperCase().equals("?DEBUG")) {
      dvDuet.sendCommand("DEBUG-" + _pjLink.getPrintDebug());
    } else if (command.toUpperCase().equals("DISABLE_POLLING")) {
      if (value.equals("1") || value.toUpperCase().equals("TRUE")) {
        _pjLink.setDisablePolling(true);
        System.out.println("Polling disabled for device " + dvDuet.getDPS().toString() + ".");
      } else if (value.equals("0") || value.toUpperCase().equals("FALSE")) {
        _pjLink.setDisablePolling(false);
        System.out.println("Polling enabled for device " + dvDuet.getDPS().toString() + ".");
      }
    } else if (command.toUpperCase().equals("?DISABLE_POLLING")) {
      dvDuet.sendCommand("DISABLE_POLLING-" + _pjLink.getDisablePolling());
    } else if (command.toUpperCase().equals("REFRESH_INTERVAL")) {
      try {
        _pjLink.setRefreshInterval(Integer.parseInt(value));
      } catch (NumberFormatException ex) {
        // Don't care.
      }
    } else if (command.toUpperCase().equals("?REFRESH_INTERVAL")) {
      dvDuet.sendCommand("REFRESH_INTERVAL-" + _pjLink.getRefreshInterval());
    }
  }
  public void deviceStateChanged(PJLink source, PJLinkEvent e) {
    switch (e.getEventType()) {
      case PJLinkEvent.EVENT_ERROR:
        int error = e.getEventData();

        if (error == 0) {
          dvDuet.offOutputChannel(CHAN_ERROR_PROJECTOR_FAILURE);
          dvDuet.offFeedbackChannel(CHAN_ERROR_PROJECTOR_FAILURE);
        }

        if ((error
                & (PJLink.ERROR_PROJECTOR_FAILURE
                    | PJLink.ERROR_COVER_ERROR
                    | PJLink.ERROR_FAN_ERROR
                    | PJLink.ERROR_FILTER_ERROR
                    | PJLink.ERROR_LAMP_ERROR
                    | PJLink.ERROR_OTHER_ERROR
                    | PJLink.ERROR_TEMP_ERROR))
            > 0) {
          dvDuet.onOutputChannel(CHAN_ERROR_PROJECTOR_FAILURE);
          dvDuet.onFeedbackChannel(CHAN_ERROR_PROJECTOR_FAILURE);
          System.out.println(
              "PJLink projector failure. "
                  + dvDuet.getDPS().toString()
                  + " - "
                  + source.getIPAddress());
        }

        if ((error & PJLink.ERROR_CONNECTION) > 0) {
          if (_pjLink.getConnectionError() == true) {
            dvDuet.onOutputChannel(CHAN_ERROR_CONNECTION);
            dvDuet.onFeedbackChannel(CHAN_ERROR_CONNECTION);
          } else {
            dvDuet.offOutputChannel(CHAN_ERROR_CONNECTION);
            dvDuet.offFeedbackChannel(CHAN_ERROR_CONNECTION);
          }
        }

        if ((error & PJLink.ERROR_FAN_WARNING) > 0) {
          dvDuet.onOutputChannel(CHAN_ERROR_FAN_WARNING);
          dvDuet.onFeedbackChannel(CHAN_ERROR_FAN_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_FAN_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FAN_ERROR);
        } else if ((error & PJLink.ERROR_FAN_ERROR) > 0) {
          dvDuet.offOutputChannel(CHAN_ERROR_FAN_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FAN_WARNING);
          dvDuet.onOutputChannel(CHAN_ERROR_FAN_ERROR);
          dvDuet.onFeedbackChannel(CHAN_ERROR_FAN_ERROR);
        } else {
          dvDuet.offOutputChannel(CHAN_ERROR_FAN_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FAN_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_FAN_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FAN_ERROR);
        }

        if ((error & PJLink.ERROR_LAMP_WARNING) > 0) {
          dvDuet.onOutputChannel(CHAN_ERROR_LAMP_WARNING);
          dvDuet.onFeedbackChannel(CHAN_ERROR_LAMP_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_LAMP_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_LAMP_ERROR);
        } else if ((error & PJLink.ERROR_LAMP_ERROR) > 0) {
          dvDuet.offOutputChannel(CHAN_ERROR_LAMP_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_LAMP_WARNING);
          dvDuet.onOutputChannel(CHAN_ERROR_LAMP_ERROR);
          dvDuet.onFeedbackChannel(CHAN_ERROR_LAMP_ERROR);
        } else {
          dvDuet.offOutputChannel(CHAN_ERROR_LAMP_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_LAMP_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_LAMP_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_LAMP_ERROR);
        }

        if ((error & PJLink.ERROR_TEMP_WARNING) > 0) {
          dvDuet.onOutputChannel(CHAN_ERROR_TEMP_WARNING);
          dvDuet.onFeedbackChannel(CHAN_ERROR_TEMP_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_TEMP_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_TEMP_ERROR);
        } else if ((error & PJLink.ERROR_TEMP_ERROR) > 0) {
          dvDuet.offOutputChannel(CHAN_ERROR_TEMP_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_TEMP_WARNING);
          dvDuet.onOutputChannel(CHAN_ERROR_TEMP_ERROR);
          dvDuet.onFeedbackChannel(CHAN_ERROR_TEMP_ERROR);
        } else {
          dvDuet.offOutputChannel(CHAN_ERROR_TEMP_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_TEMP_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_TEMP_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_TEMP_ERROR);
        }

        if ((error & PJLink.ERROR_COVER_WARNING) > 0) {
          dvDuet.onOutputChannel(CHAN_ERROR_COVER_WARNING);
          dvDuet.onFeedbackChannel(CHAN_ERROR_COVER_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_COVER_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_COVER_ERROR);
        } else if ((error & PJLink.ERROR_COVER_ERROR) > 0) {
          dvDuet.offOutputChannel(CHAN_ERROR_COVER_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_COVER_WARNING);
          dvDuet.onOutputChannel(CHAN_ERROR_COVER_ERROR);
          dvDuet.onFeedbackChannel(CHAN_ERROR_COVER_ERROR);
        } else {
          dvDuet.offOutputChannel(CHAN_ERROR_COVER_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_COVER_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_COVER_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_COVER_ERROR);
        }

        if ((error & PJLink.ERROR_FILTER_WARNING) > 0) {
          dvDuet.onOutputChannel(CHAN_ERROR_FILTER_WARNING);
          dvDuet.onFeedbackChannel(CHAN_ERROR_FILTER_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_FILTER_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FILTER_ERROR);
        } else if ((error & PJLink.ERROR_FILTER_ERROR) > 0) {
          dvDuet.offOutputChannel(CHAN_ERROR_FILTER_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FILTER_WARNING);
          dvDuet.onOutputChannel(CHAN_ERROR_FILTER_ERROR);
          dvDuet.onFeedbackChannel(CHAN_ERROR_FILTER_ERROR);
        } else {
          dvDuet.offOutputChannel(CHAN_ERROR_FILTER_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FILTER_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_FILTER_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_FILTER_ERROR);
        }

        if ((error & PJLink.ERROR_OTHER_WARNING) > 0) {
          dvDuet.onOutputChannel(CHAN_ERROR_OTHER_WARNING);
          dvDuet.onFeedbackChannel(CHAN_ERROR_OTHER_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_OTHER_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_OTHER_ERROR);
        } else if ((error & PJLink.ERROR_OTHER_ERROR) > 0) {
          dvDuet.offOutputChannel(CHAN_ERROR_OTHER_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_OTHER_WARNING);
          dvDuet.onOutputChannel(CHAN_ERROR_OTHER_ERROR);
          dvDuet.onFeedbackChannel(CHAN_ERROR_OTHER_ERROR);
        } else {
          dvDuet.offOutputChannel(CHAN_ERROR_OTHER_WARNING);
          dvDuet.offFeedbackChannel(CHAN_ERROR_OTHER_WARNING);
          dvDuet.offOutputChannel(CHAN_ERROR_OTHER_ERROR);
          dvDuet.offFeedbackChannel(CHAN_ERROR_OTHER_ERROR);
        }

        break;

      case PJLinkEvent.EVENT_POWER:
        // Lamp channel feedback.
        if (e.getEventData() == PJLink.POWER_ON || e.getEventData() == PJLink.POWER_WARMING) {
          dvDuet.onOutputChannel(CHAN_LAMP);
          dvDuet.onFeedbackChannel(CHAN_LAMP);
        } else {
          dvDuet.offOutputChannel(CHAN_LAMP);
          dvDuet.offFeedbackChannel(CHAN_LAMP);
        }

        // Warming channel feedback.
        if (e.getEventData() == PJLink.POWER_WARMING) {
          dvDuet.onOutputChannel(CHAN_WARMING);
          dvDuet.onFeedbackChannel(CHAN_WARMING);
        } else {
          dvDuet.offOutputChannel(CHAN_WARMING);
          dvDuet.offFeedbackChannel(CHAN_WARMING);
        }

        // Cooling channel feedback.
        if (e.getEventData() == PJLink.POWER_COOLING) {
          dvDuet.onOutputChannel(CHAN_COOLING);
          dvDuet.onFeedbackChannel(CHAN_COOLING);
        } else {
          dvDuet.offOutputChannel(CHAN_COOLING);
          dvDuet.offFeedbackChannel(CHAN_COOLING);
        }
        break;

      case PJLinkEvent.EVENT_INPUT:
        int active = e.getEventData();

        for (int i = CHAN_INPUT_RGB_1; i <= CHAN_INPUT_NETWORK_9; i++) {
          if (i == active + 300) {
            dvDuet.onOutputChannel(i);
            dvDuet.onFeedbackChannel(i);
          } else {
            dvDuet.offOutputChannel(i);
            dvDuet.offFeedbackChannel(i);
          }
        }
        break;

      case PJLinkEvent.EVENT_LAMP:
        dvDuet.sendCommand("LAMPTIME-" + e.getEventData());
        break;

      case PJLinkEvent.EVENT_AV_MUTE:
        switch (e.getEventData()) {
          case PJLink.MUTE_OFF:
            dvDuet.offOutputChannel(CHAN_AUDIO_MUTE);
            dvDuet.offFeedbackChannel(CHAN_AUDIO_MUTE);
            dvDuet.offOutputChannel(CHAN_PICTURE_MUTE);
            dvDuet.offFeedbackChannel(CHAN_PICTURE_MUTE);
            break;

          case PJLink.MUTE_AUDIO_VIDEO:
            dvDuet.onOutputChannel(CHAN_AUDIO_MUTE);
            dvDuet.onFeedbackChannel(CHAN_AUDIO_MUTE);
            dvDuet.onOutputChannel(CHAN_PICTURE_MUTE);
            dvDuet.onFeedbackChannel(CHAN_PICTURE_MUTE);
            break;

          case PJLink.MUTE_VIDEO_ONLY:
            dvDuet.offOutputChannel(CHAN_AUDIO_MUTE);
            dvDuet.offFeedbackChannel(CHAN_AUDIO_MUTE);
            dvDuet.onOutputChannel(CHAN_PICTURE_MUTE);
            dvDuet.onFeedbackChannel(CHAN_PICTURE_MUTE);
            break;

          case PJLink.MUTE_AUDIO_ONLY:
            dvDuet.onOutputChannel(CHAN_AUDIO_MUTE);
            dvDuet.onFeedbackChannel(CHAN_AUDIO_MUTE);
            dvDuet.offOutputChannel(CHAN_PICTURE_MUTE);
            dvDuet.offFeedbackChannel(CHAN_PICTURE_MUTE);
            break;

          default:
            break;
        }
        break;

      default:
        break;
    }
  }