/**
* Copyright 2014 Comcast Cable Communications Management, LLC
*
* This file is part of CATS.
*
* CATS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CATS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CATS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.comcast.cats.service.power;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
public class NetBooter_NP_16S_PowerDevice extends NetBooter_PowerDevice {
private PowerDeviceConnectionNP16S client;
/**
* Small delay used between connection and sending a command to the hardware.
*/
public static final int PAUSE_BETWEEN_CMD = 1000;
/**
* The return code of OK.
*/
public static final String OK = "$A0";
/**
* The power command used for outlet state control.
*/
public static final String PWRCMD = "$A3";
/**
* The reboot command used for outlet toggling.
*/
public static final String REBOOT = "$A4";
/**
* The command to display outlet status.
*/
public static final String OUTLETSTATUS = "$A5";
/**
* The ON state for the outlet.
*/
public static final String ONSTATE = "1";
/**
* The OFF state for the outlet.
*/
public static final String OFFSTATE = "0";
private static final int CONNECT_TIMEOUT = 10000;
private static final int READ_WAIT = 500;
private static final Logger log = LoggerFactory.getLogger(NetBooter_NP_16S_PowerDevice.class);
public NetBooter_NP_16S_PowerDevice() {
}
//This constructor is used in testing only.
public NetBooter_NP_16S_PowerDevice(String ip, int port, int numOutlets) {
this.ip = ip;
this.port = port;
this.numOutlets = numOutlets;
}
/**
* Method to initialize the power device connection.
*/
@Override
public void createPowerDevConn() {
log.debug("Creating the connection to the NP-16S power device.");
client = null;
client = new PowerDeviceConnectionNP16S(getIp(), getPort());
client.setInitialCR(true);
}
/**
* Setter method for the device IP.
*
* @param ip
* The ip string representation for the device.
*/
@Override
public void setIp(String ip) {
super.setIp(ip);
if (null != client && client.isConnected()) {
client.close();
}
createPowerDevConn();
}
/**
* Setter method for the device port.
*
* @param port
* The port number for the device.
*/
@Override
public void setPort(int port) {
super.setPort(port);
if (null != client && client.isConnected()) {
client.close();
}
createPowerDevConn();
}
@Override
public void destroy() {
client.close();
}
/**
* The main power command used for changing the outlet power state.
*
* @param cmd
* The command to perform (ON, OFF, or BOOT).
* @param outlet
* The outlet number.
* @return true if the power state was changed successfully, false otherwise.
*/
public boolean power(String cmd, final int outlet) {
assert (null != cmd);
cmd = cmd.trim();
if (outlet < 0 || outlet > getNumOutlets()) {
throw new java.lang.IllegalArgumentException("Invalid outlet number: "
+ outlet);
}
String np_command;
if (cmd.equalsIgnoreCase(OFF)) {
np_command = PWRCMD + " " + outlet + " " + OFFSTATE;
}
else if (cmd.equalsIgnoreCase(ON)) {
np_command = PWRCMD + " " + outlet + " " + ONSTATE;
}
else if (cmd.equalsIgnoreCase(BOOT)) {
np_command = REBOOT + " " + outlet;
}
else {
throw new java.lang.IllegalArgumentException(
"Invalid command argument: " + cmd);
}
log.debug("Sending command: [" + np_command + "]");
if (client.connect(CONNECT_TIMEOUT)) {
sleep(PAUSE_BETWEEN_CMD);
String response = client.read(READ_WAIT);
client.sendCmd(np_command, true);
sleep(PAUSE_BETWEEN_CMD);
response = client.waitForString(OK, READ_WAIT);
client.close();
if (response.indexOf(OK) != -1) {
updateStatistics(outlet, cmd, true);
return true;
}
}
updateStatistics(outlet, cmd, false);
return false;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized String getOutletStatus(int outlet) {
String status = "UNKNOWN";
String addr = client.getInetAddress().toString();
if (client.connect(CONNECT_TIMEOUT)) {
sleep(PAUSE_BETWEEN_CMD);
String response = client.read(READ_WAIT);
if (!client.sendCmd(OUTLETSTATUS, true)) {
log.warn("Status request failed." + addr);
client.close();
return status;
}
sleep(PAUSE_BETWEEN_CMD);
response = client.read(READ_WAIT);
client.close();
log.debug("Power device respones from " + addr + ": [" + response + "]");
if (-1 == response.indexOf(OK)) {
log.error("OK not found: " + addr + ": [" + response + "]");
return status;
}
int firstComma = response.indexOf(",");
if (-1 == firstComma) {
log.error("First comma not found: " + addr + ": [" + response + "]");
return status;
}
int secondComma = response.indexOf(",", firstComma + 1);
if (-1 == secondComma) {
log.error("Second comma not found: " + addr + ": [" + response + "]");
return status;
}
String outletStatus = response.substring(firstComma + 1, secondComma);
byte[] outletStatusArray = outletStatus.getBytes();
// The original status String was in reverse order (outlet 1 on the
// right).
char st = (char) outletStatusArray[outletStatusArray.length - outlet];
if ('1' == st) {
return ON;
}
else if ('0' == st) {
return OFF;
}
else {
log.error("Unknown status: " + addr + ": [" + response + "] status: " + st);
return status;
}
}
else {
log.error("Could not connect to client. " + addr);
}
return status;
}
}