/**
* 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.Logger;
import org.slf4j.LoggerFactory;
import com.comcast.cats.service.PowerInfo;
import com.comcast.cats.service.PowerStatistics;
/**
* A PowerControllerDevice that controls a WTI_IPS_1600 power bar.
*/
public class WTI_IPS_1600_PowerDevice extends PowerControllerDevice {
PowerDeviceConnection client;
/**
* On message. Used to turn on the device.
*/
public static final String ON = "/ON";
/**
* Off message. Used to turn off the device.
*/
public static final String OFF = "/OFF";
/**
* Boot message. Used to power toggle the device.
*/
public static final String BOOT = "/BOOT";
/**
* Prompt message.
*/
public static final String PROMPT = "IPS";
/**
* Disconnect message.
*/
public static final String DISCONNECT = "/X";
/**
* Plug status message.
*/
public static final String PLUGSTATUS = "/S";
private int responseTime = 5000;
private static final int CONNECT_TIMEOUT = 5000;
private final Logger log = LoggerFactory.getLogger(WTI_IPS_1600_PowerDevice.class);
private PowerInfo powerInfo = null;
public WTI_IPS_1600_PowerDevice() {
}
public WTI_IPS_1600_PowerDevice(String ip, int port, int numOutlets) {
this.ip = ip;
this.port = port;
this.numOutlets = numOutlets;
}
/**
* Creates a power device connection based on the set IP and Port.
*/
@Override
public void createPowerDevConn() {
client = null;
client = new PowerDeviceConnection(getIp(), getPort());
client.setInitialCR(true);
}
/**
* {@inheritDoc}
*/
@Override
public synchronized boolean powerOn(final int outlet) {
boolean ret = power(ON, outlet);
updateStatistics(outlet, ON, ret);
return ret;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized boolean powerOff(final int outlet) {
boolean ret = power(OFF, outlet);
updateStatistics(outlet, OFF , ret);
return ret;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized boolean powerToggle(int outlet) {
boolean ret = power(BOOT, outlet);
System.out.println(" Inside BOOT in WTI_IPS_1600_Device");
updateStatistics(outlet, BOOT, ret);
return ret;
}
/**
* Sends the specified command to the specified outlet.
* A valid IP and Port must be set before using this command otherwise it will fail.
* @param cmd The command. Must be /OFF, /ON, or /BOOT
* @param outlet The outlet. Must be > 0 and <= the number of outlets.
* @return <b>true</b> on success.
*/
public boolean power(String cmd, final int outlet) {
if (getState().equals(PowerControllerDevice.OFF)) {
log.warn("This device is currently disabled.");
return false;
}
cmd = cmd.trim();
if (!cmd.equalsIgnoreCase(OFF) && !cmd.equalsIgnoreCase(ON)
&& !cmd.equalsIgnoreCase(BOOT)) {
throw new java.lang.IllegalArgumentException(
"Invalid command argument: " + cmd);
}
if (outlet < 0 || outlet > getNumOutlets()) {
throw new java.lang.IllegalArgumentException("Invalid outlet number: "
+ outlet);
}
cmd = cmd + " " + outlet;
if (client.connect(CONNECT_TIMEOUT)) {
String response = client.waitForString(PROMPT, responseTime);
if (response.indexOf(PROMPT) != -1) {
response = "";
if (client.sendCmd(cmd, true)) {
response = client.waitForString(PROMPT, responseTime);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
log.error("Sleeping was interrupted");
}
if (response.indexOf(PROMPT) != -1) {
client.close();
return true;
}
}
}
}
client.close();
return false;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized String getOutletStatus(int outlet) {
String status = "UNKNOWN";
if (client.connect(CONNECT_TIMEOUT) && client.sendCmd(PLUGSTATUS, false)) {
final int WAIT = 1000; // don't need much time for this.
String response = client.read(WAIT);
if (null != response && !response.isEmpty()) {
String[] tableArray = response.split("-----\\+------------------\\+-------------\\+--------\\+-----------------\\+---------\\+");
if (tableArray.length != 3) {
// client.close();
log.error("Unknown table format, cannot parse");
return status;
} else {
/* The second element of the split table should be
* a table of each outlet status.
* Format is as follows:
* Plug | Name | Password | Status | Boot/Seq. Delay | Default |
*
* We are interested in the plug (outlet #) and the status only.
*/
response = tableArray[1];
}
final int COL_COUNT = 6;
final int OUTLET_COL = 0;
final int STATUS_COL = 3;
String[] splitRows = response.trim().split("\\|");
int rowCount = splitRows.length / COL_COUNT;
for (int row = 0; row <= rowCount; ++row) {
String outletStr = "";
String statusStr = "";
try {
outletStr = splitRows[OUTLET_COL + (row * COL_COUNT)].trim();
statusStr = splitRows[STATUS_COL + (row * COL_COUNT)].trim();
if (outlet == Integer.parseInt(outletStr)) {
if (statusStr.equals(PowerControllerDevice.OFF) || statusStr.equals(PowerControllerDevice.ON)) {
status = statusStr;
break;
} else {
log.info("Invalid status found: " + statusStr);
break;
}
}
} catch (NumberFormatException npe) {
log.error("NumberFormatException parsing " + outletStr + " row format may have changed.");
} catch (IndexOutOfBoundsException iob) {
log.error("IndexOutOfBoundsException table format may have changed.");
}
}
}
} else {
if (!client.isConnected()) {
log.warn("Could not connect to client.");
} else {
log.warn("Status request failed.");
}
}
client.close();
return status;
}
/**
* Set the IP address.
* This also calls createPowerDevConn() to create a connection with the new IP.
* @param ip the ip to set.
*/
@Override
public void setIp(String ip) {
super.setIp(ip);
createPowerDevConn();
}
/**
* Sets the port.
* This also calls createPowerDevConn() to create a connection with the new port.
* @param port the port to set.
*/
@Override
public void setPort(int port) {
super.setPort(port);
createPowerDevConn();
}
@Override
public void destroy() {
log.info("Destroying the connection for"+getIp());
client.close();
}
}