/** * 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 java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.SocketException; import org.apache.commons.net.telnet.TelnetClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static com.comcast.cats.service.power.util.PowerConstants.NEWLINE; import static com.comcast.cats.service.power.util.PowerConstants.NPS_PROMPT; import static com.comcast.cats.service.power.util.PowerConstants.LOGIN; import static com.comcast.cats.service.power.util.PowerConstants.PASSWORD; import static com.comcast.cats.service.power.util.PowerConstants.SLASH; import static com.comcast.cats.service.power.util.PowerConstants.CMD_TO_SUPPRESS_CONFIRMATION_PROMPT; import static com.comcast.cats.service.power.util.PowerConstants.SPACE; import static com.comcast.cats.service.power.util.PowerConstants.POWER_ON; import static com.comcast.cats.service.power.util.PowerConstants.POWER_OFF; import static com.comcast.cats.service.power.util.PowerConstants.POWER_BOOT; import static com.comcast.cats.service.power.util.PowerConstants.STATUS_UNKNOWN; import static com.comcast.cats.service.power.util.PowerConstants.PLUG_STATUS_CMD; import static com.comcast.cats.service.power.util.PowerConstants.POWER_STATUS_ONE; import static com.comcast.cats.service.power.util.PowerConstants.POWER_STATUS_ZERO; public class WTI_NPS_1600_PowerDevice extends PowerControllerDevice { private static final Logger log = LoggerFactory.getLogger( PowerDeviceConnection.class ); private String host; private Integer port; private String username; private String password; private TelnetClient client; private InputStream in; private OutputStream out; private String lastString; public WTI_NPS_1600_PowerDevice( String host, Integer port, String username, String password ) { this.host = host; this.port = port; this.username = username; this.password = password; } protected boolean sendCmd( String cmd, boolean echo ) { if ( !cmd.endsWith( NEWLINE ) ) { cmd += NEWLINE; } try { if ( null != this.out ) { out.write( cmd.getBytes() ); if ( echo ) { log.info( "writing to " + host + ": " + cmd ); } out.flush(); return true; } } catch ( IOException ioe ) { log.error( "IOException: " + ioe.getMessage() ); } return false; } /** *This method reads a character at a time from the socket input stream * until EOF is reached, or the substring of the search string is found. * Once string is found the input stream is interrupted Immediately and * returns * * @return true, if string is found, else false. */ protected boolean waitFor( String str ) { StringBuilder buff = new StringBuilder(); int c; try { try { Thread.sleep( 100 ); } catch ( InterruptedException e ) { // TODO Auto-generated catch block e.printStackTrace(); } c = in.read(); while ( -1 != c ) { buff.append( ( char ) c ); if ( buff.indexOf( str ) != -1 ) { log.debug( "Found: '" + str + "'" ); lastString = buff.toString(); return true; } c = in.read(); } lastString = buff.toString(); } catch ( IOException ioe ) { log.error( "IOException: " + ioe.getMessage() ); } return false; } /** * This device requires login, which is different than previous devices. */ protected boolean login() { if ( !waitFor( LOGIN ) ) { return false; } sendCmd( username, true ); if ( !waitFor( PASSWORD ) ) { return false; } sendCmd( password, true ); return waitFor( NPS_PROMPT ); } private boolean sendPowerCommand( String command, int outlet ) { boolean send = sendCmd( SLASH + command + SPACE + outlet + CMD_TO_SUPPRESS_CONFIRMATION_PROMPT, true ); if ( send && waitFor( NPS_PROMPT ) ) { return true; } return false; } @Override public boolean powerOn( int outlet ) { log.info("POWER ON in WTI_NPS_1600_PowerDevice"); boolean result = sendPowerCommand( POWER_ON, outlet ); return result; } @Override public boolean powerOff( int outlet ) { log.info("POWER OFF in WTI_NPS_1600_PowerDevice"); boolean result = sendPowerCommand( POWER_OFF, outlet ); return result; } @Override public boolean powerToggle( int outlet ) { log.info(" POWER REBOOT in WTI_NPS_1600_PowerDevice "); boolean result = sendPowerCommand( POWER_BOOT, outlet ); return result; } /** * Status looks like this: /S <outlet>\r\n [0|1] - '0' or '1' NPS> //Back to * prompt. * * @return */ protected String parseStatus() { // Wait for the previous end of the last command. waitFor( NEWLINE ); // Wait for the new NPS command. waitFor( NPS_PROMPT ); // Before the NPS command the status should have been outputted as // either '0' or '1', so let's look for it. if ( lastString.contains( POWER_STATUS_ZERO ) ) { return POWER_OFF; } else if ( lastString.contains( POWER_STATUS_ONE ) ) { return POWER_ON; } return STATUS_UNKNOWN; } @Override public String getOutletStatus( int outlet ) { sendCmd( PLUG_STATUS_CMD + outlet, true ); return parseStatus(); } public boolean logout() { boolean returnVal = true; try { client.disconnect(); } catch ( IOException e ) { log.error( "IOException :"+e ); } return returnVal; } @Override public void createPowerDevConn() { client = new TelnetClient(); client.setConnectTimeout( 5000 ); try { client.connect( host, port ); } catch ( SocketException socketException ) { throw new UnableToCreatePowerControllerDevice( socketException ); } catch ( IOException ioException ) { throw new UnableToCreatePowerControllerDevice( ioException ); } in = client.getInputStream(); out = client.getOutputStream(); login(); } @Override public void destroy() { // TODO Auto-generated method stub } }