001/* 002 * $HeadURL: svn://svn.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/tools/isy/ISY99Buttons.java $ 003 * $Revision: 1031 $ 004 * $Date: 2015-11-08 19:13:25 -0800 (Sun, 08 Nov 2015) $ 005 * $Author: tgutwin $ 006 */ 007 008/* 009 * IsyButtons -- A simple Panel control pad that turns on/off Insteon 010 * devices and scenes.. 011 * 012 * Copyright (C) 2010-2013 WebARTS Design, North Vancouver Canada 013 * http://www.webarts.bc.ca 014 * 015 * This program is free software; you can redistribute it and/or modify 016 * it under the terms of Version 2 of the GNU General Public License as 017 * published by the Free Software Foundation. 018 * 019 * This program is distributed in the hope that it will be useful, 020 * but WITHOUT ANY WARRANTY; without even the implied warranty of 021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 022 * GNU General Public License for more details. 023 * 024 * You should have received a copy of the GNU General Public License 025 * along with this program; if not, write to the Free Software 026 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 027 */ 028package ca.bc.webarts.tools.isy; 029 030import ca.bc.webarts.widgets.ColouredLabel; 031import ca.bc.webarts.widgets.JToggleButton; 032import ca.bc.webarts.widgets.Util; 033 034import java.awt.BorderLayout; 035import java.awt.Color; 036import java.awt.Dimension; 037import java.awt.FlowLayout; 038import java.awt.Font; 039import java.awt.GridLayout; 040import java.awt.event.ActionEvent; 041import java.awt.event.ActionListener; 042import java.awt.event.MouseAdapter; 043import java.awt.event.MouseEvent; 044import java.awt.event.MouseListener; 045import java.awt.event.MouseMotionAdapter; 046import java.io.File; 047import java.util.ArrayList; 048import java.util.Enumeration; 049import java.util.Iterator; 050import java.util.NoSuchElementException; 051import java.util.Set; 052import java.util.StringTokenizer; 053import java.util.Vector; 054import javax.swing.BorderFactory; 055import javax.swing.ButtonGroup; 056import javax.swing.ImageIcon; 057import javax.swing.JButton; 058import javax.swing.JCheckBox; 059import javax.swing.JPopupMenu; 060import javax.swing.JRadioButton; 061import javax.swing.JOptionPane; 062import javax.swing.JPanel; 063import javax.swing.JSpinner; 064import javax.swing.JWindow; 065import javax.swing.SpinnerListModel; 066import javax.swing.border.BevelBorder; 067import javax.swing.border.EmptyBorder; 068 069import com.udi.insteon.client.InsteonConstants; 070import com.universaldevices.client.NoDeviceException; 071import com.universaldevices.common.UDUtil; 072import com.universaldevices.device.model.ProductInfo; 073import com.universaldevices.device.model.UDGroup; 074import com.universaldevices.device.model.UDControl; 075import com.universaldevices.device.model.UDNode; 076import com.universaldevices.resources.errormessages.Errors; 077 078/** 079 * A simple window widget that holds a bunch of buttons that directly turn an 080 * Insteon device on or off via a Universal Devices ISy-99i. This app requires 081 * a few other libraries: webarts, and 082 * kiwi java libraries as well as the UDI JSDK 083 * implementation on your system. 084 * 085 * @author tgutwin 086 */ 087public class ISY99Buttons extends JWindow implements ActionListener 088{ 089 /** A Class holder for its name (used in Logging). */ 090 private static String className_ = "ISY99Buttons"; 091 092 /** A holder for this clients System File Separator. */ 093 public final static String SYSTEM_FILE_SEPERATOR = File.separator; 094 095 /** A holder for this clients System line termination separator. */ 096 public final static String SYSTEM_LINE_SEPERATOR = 097 System.getProperty("line.separator"); 098 private IsyInsteonClient myISY = null; 099 private boolean stillRunning_ = false; 100 private boolean finishedStartup_ = false; 101 102 private String[] insteonAddresses_ = {"14.2B.31.1"}; 103 private String[] insteonResponderAddresses_ = {"14.2B.31.1"}; 104 private String[] insteonResponderNames_ = {"Device1"}; 105 106 /** The last device button pressed - used for dim/bright. */ 107 private String lastDevice_=""; 108 109 // Colours 110 /** The colour used for all panels except the display area. */ 111 static Color mainBackColour_ = new Color( 100, 180, 245 ); 112 /** The colour used to back the display area. */ 113 static Color displayBackColour_ = Color.black; 114 /** The display area text colour. */ 115 static Color displayTextColour_ = mainBackColour_.brighter(); 116 117 /** The Main Popup menu */ 118 static JPopupMenu mainMenu = new JPopupMenu( className_ + " Main Menu" ); 119 120 /** Popup menu Mouse Listener. */ 121 static MouseListener popupListener_ = 122 new MouseAdapter() 123 { 124 public void mousePressed( MouseEvent e ) 125 { 126 maybeShowPopup( e ); 127 } 128 129 public void mouseReleased( MouseEvent e ) 130 { 131 maybeShowPopup( e ); 132 } 133 134 private void maybeShowPopup( MouseEvent e ) 135 { 136 if ( e.isPopupTrigger() ) 137 { 138 mainMenu.show( e.getComponent(), e.getX(), e.getY() ); 139 } 140 } 141 }; 142 143 144 /** The wrapper panel holding all in this JWindow. */ 145 JPanel dragableMiniViewPanel = new JPanel(); 146 /** The Button area wrapper inside the dragableMiniViewPanel. */ 147 JPanel miniViewPanel = new JPanel(); 148 /** The Control area at the top of the window. */ 149 JPanel miniViewWindowControlPanel = new JPanel(); 150 /** The window header / draggable button. */ 151 JButton miniDragButton = new JButton( "" ); 152 /** The button to Min/Max this mini app window */ 153 JButton miniButtonView_ = new JButton( "" ); 154 /** The button to close this mini app window. */ 155 JButton miniButtonClose_ = new JButton( "" ); 156 /** The panel holding the X10 buttons */ 157 JPanel miniButtonPanel_ = new JPanel(); 158 /** The panel holding the on/off toggle button */ 159 JPanel dimPanel_ = new JPanel(); 160 /** The object holding the min/max icon. */ 161 ImageIcon iconMiniView_ = new ImageIcon(); 162 /** The object holding the close icon. */ 163 ImageIcon iconMiniClose_ = new ImageIcon(); 164 /** The object holding the dim icon. */ 165 ImageIcon iconDim_ = new ImageIcon(); 166 /** The object holding the bright icon. */ 167 ImageIcon iconBright_ = new ImageIcon(); 168 /** The X amount the current window was just dragged. */ 169 private int XDifference_; 170 /** The Y amount the current window was just dragged. * */ 171 private int YDifference_; 172 /** the x position of the mini window. * */ 173 private int xPosition_ = 100; 174 /** the y position of the mini window. * */ 175 private int yPosition_ = 100; 176 /** the x position of the app window. * */ 177 private int appXpos = -1; 178 /** the y position of the app window. * */ 179 private int appYpos = -1; 180 /** the number of rows of buttons to display in the app window. * */ 181 private int displayRows_ = 0; // zero means any amount needed 182 /** the number of columns of buttons to display in the app window. * */ 183 private int displayCols_ = 3; 184 /** Class var holding the number of buttons * */ 185 private int numButtons_ = insteonResponderAddresses_.length; 186 187 /** The dir where the images are located. */ 188 String IMAGE_DIR = "." + SYSTEM_FILE_SEPERATOR + 189 "images" + SYSTEM_FILE_SEPERATOR; 190 191 /** The Extension for the button images * */ 192 String buttonImageExtension_ = ".gif"; 193 194 /** The Extension for the button images * */ 195 String buttonImagepath_ = "/images/org/javalobby/icons/20x20/Circle_"; 196 197 /** This is this apps draggable - Title bar. */ 198 ColouredLabel miniDragLabel = new ColouredLabel( 199 displayBackColour_, 200 displayTextColour_, 201 new Font( "Arial", Font.PLAIN, 10 ), 202 " <-- ISY994i Buttons --> " ); 203 204 /** An array of the buttons. */ 205 JButton[] controlButton_ = null; 206 207 /** A dim button. */ 208 JButton dimButton_ = new JButton( "" ); 209 210 /** A dim button. */ 211 JButton brightButton_ = new JButton( "" ); 212 213 /** The toggle controlling if the next command will be on or Off. */ 214 JToggleButton onOffToggle_ = new JToggleButton(); 215 216 ImageIcon onIcon = new ImageIcon( Util.loadImage( "/images/org/javalobby/icons/20x20/BulbOn.gif" ), "On " + className_ ); 217 ImageIcon offIcon = new ImageIcon( Util.loadImage( "/images/org/javalobby/icons/20x20/BulbOff.gif" ), "Off " + className_ ); 218 219 /** 220 * Listener for when the mouse is pressed on the fake window frame title bar 221 * button. 222 */ 223 MouseAdapter miniViewMouseListener = 224 new MouseAdapter() 225 { 226 /** 227 * the impl for a mouse press. 228 * 229 * @param e Description of Parameter 230 * @since 231 */ 232 public void mousePressed( MouseEvent e ) 233 { 234 XDifference_ = e.getX(); 235 YDifference_ = e.getY(); 236 } 237 }; 238 239 /** Listener for changing the location of this window. * */ 240 MouseMotionAdapter dragMiniViewMotionListener = 241 new MouseMotionAdapter() 242 { 243 /** 244 * Implementation of the mouse dragged event handler. 245 * 246 * @param e Description of Parameter 247 * @since 248 */ 249 public void mouseDragged( MouseEvent e ) 250 { 251 setLocation( xPosition_ + ( e.getX() - XDifference_ ), 252 yPosition_ + ( e.getY() - YDifference_ ) ); 253 xPosition_ = xPosition_ + ( e.getX() - XDifference_ ); 254 yPosition_ = yPosition_ + ( e.getY() - YDifference_ ); 255 } 256 }; 257 258 259 /** The thread that the isyDevice runs in. **/ 260 private Thread startupThread_ = new Thread () 261 { 262 public void run() 263 { 264 myISY.start(); 265 } 266 }; 267 268 269 /** The thread that watches for changes to the nodes being displayed. It then keeps the icon indicators in sync with actual. **/ 270 private Thread nodeWatcherThread_ = new Thread () 271 { 272 public void run() 273 { 274 System.out.println("\n *!*! Watching for nodeChanges..."); 275 UDUtil.sleep(750); 276 ArrayList<NodeChangeMessage> msgs = null; 277 int i = 0; 278 boolean notFound = true; 279 //NodeChangeMessage currMsg = null; 280 //timeOut+=1000; 281 while (startupThread_!=null) 282 { 283 // Get the latest Changes 284 msgs = myISY.getRecentNodeChanges(); 285 286 287 // Update the icons 288 if (msgs!=null && finishedStartup_) // ignore the 1st time through 289 { 290 for (NodeChangeMessage currMsg:msgs) 291 { 292 if (currMsg!=null) 293 { 294 //System.out.println(" *!*! "+msgs.size()+ " nodeChanges..."); 295 //currMsg = (NodeChangeMessage)msgs.get(0); 296 UDControl msgControl = currMsg.getControl(); 297 Object msgValue = currMsg.getValue(); 298 UDNode msgNode = currMsg.getNode(); 299 300 /* 301 System.out.println(" "+ 302 (msgNode!=null?msgNode.name:"nullNode") + " changed "+ 303 (msgControl!=null?msgControl.label:"nullControl") + " to "+ 304 (msgValue!=null?""+msgValue:"nullValue") 305 ); 306 */ 307 notFound = true; 308 for ( i = 0; notFound && i < numButtons_; i++ ) 309 { 310 // NON-X10 buttons get updated 311 if (!insteonResponderNames_[i].startsWith("A")) 312 { 313 if(controlButton_[i].getText().equals((msgNode!=null?msgNode.name:"nullNode"))) 314 { 315 notFound = false; // break out early 316 // update Icon 317 if ((msgControl!=null?msgControl.label:"nullControl").equals("Status") && 318 !(msgValue!=null?""+msgValue:"nullValue").equals("0") ) 319 controlButton_[i].setIcon(onIcon); 320 if ((msgControl!=null?msgControl.label:"nullControl").equals("Status") && 321 (msgValue!=null?""+msgValue:"nullValue").equals("0") ) 322 controlButton_[i].setIcon(offIcon); 323 } 324 } 325 } 326 } 327 } 328 msgs = null; 329 } 330 else if (msgs!=null && !finishedStartup_) finishedStartup_ = true; 331 332 // wait a bit then do it again 333 UDUtil.sleep(200); 334 } 335 } 336 }; 337 338 339 /** Indicates if this class thread is still running **/ 340 public boolean stillRunning( ) 341 { 342 return this.stillRunning_; 343 } 344 345 346 /** Gets the issyClient running and waits till its running. **/ 347 public boolean startIsy( ) 348 { 349 System.out.print(" **Starting Client..."); 350 startupThread_.start(); 351 UDUtil.sleep(1500); 352 int timeOut = 0; 353 while (!myISY.isReadyToGo() && timeOut < 25000) 354 { 355 UDUtil.sleep(250); 356 timeOut+=250; 357 } 358 if (timeOut>24999) 359 System.out.println(" Startup Timed Out."); 360 else 361 System.out.println(" Startup Successful."); 362 this.stillRunning_ = myISY.isReadyToGo(); 363 if (!this.stillRunning_) 364 { 365 UDUtil.sleep(2500); 366 this.stillRunning_ = myISY.isReadyToGo(); 367 } 368 UDUtil.sleep(2500); 369 return this.stillRunning_ ; 370 } 371 372 373 /** 374 * Cleans up any ISY cleanup procedures in prep for exit. 375 */ 376 protected void isyCleanup() 377 { 378 System.out.print("\nCleaning up before Exit... "); 379 try 380 { 381 nodeWatcherThread_.stop(); 382 startupThread_ = null; 383 this.stillRunning_ = false; 384 UDUtil.sleep(250); 385 myISY.cleanUp(); 386 myISY.stop(); 387 //startupThread_.stop(); 388 //Util.sleep(5000); 389 //if (myISY.isReadyToGo()) { System.out.println(" waiting...");UDUtil.sleep(2000);} 390 391 Set<Thread> threadSet = Thread.getAllStackTraces().keySet(); 392 Thread currThread = null; 393 Iterator iter = threadSet.iterator(); 394 while (iter.hasNext()) 395 { 396 currThread = (Thread) iter.next(); 397 System.out.print(currThread.getName()); 398 try 399 { 400 if (currThread.getName().startsWith("Thread")) 401 { 402 System.out.print("[X]"); 403 currThread.interrupt(); 404 } 405 System.out.print(" "); 406 } 407 catch (Exception ex) 408 { 409 // nothing 410 } 411 } 412 } 413 catch (Exception ex) 414 { 415 // nothing 416 } 417 System.out.println("done!"); 418 419 } 420 421 422 /** 423 * Notifies the user of a syntax error 424 */ 425 protected void syntaxError() 426 { 427 System.err.println("Syntax error. Try again."); 428 } 429 430 431 /** Constructor BUT does NOT start up the Client Connection. To start use startIsy.**/ 432 public ISY99Buttons() 433 { 434 myISY = new IsyInsteonClient(true); 435 myISY.debugOn(); 436 } 437 438 439 /** 440 * The main program for the ISY99Buttons class. 441 * 442 * @param arg The command line arguments 443 */ 444 public static void main( String[] arg ) 445 { 446 System.out.println( "Starting ISY99Buttons " ); 447 ISY99Buttons instance = new ISY99Buttons(); 448 Errors.addErrorListener(new MyISYErrorHandler()); 449 450 try 451 { 452 instance.startIsy(); // this starts and BLOCKS until started 453 if (instance.stillRunning_ && instance.myISY.isReadyToGo()) 454 { 455 instance.myISY.debugOff(); 456 Thread.sleep(200); 457 instance.loadButtonNodeAddresses(); 458 instance.loadButtonNodeNames(); 459 instance.initGui(); 460 System.out.println(ca.bc.webarts.tools.isy.ISY99CLI.dumpIsyProductInfo(instance.myISY).toString()); 461 System.out.println("\n\n"); 462 } 463 else 464 { 465 // put up a dialog to say no device authentication 466 JOptionPane.showMessageDialog(null, "Could Not Find/Authenticate any UDI ISY-99 devices.\nTry Again.", 467 "Alert", JOptionPane.ERROR_MESSAGE); 468 Thread.sleep(3000); 469 if (instance.stillRunning_ && instance.myISY.isReadyToGo()) 470 { 471 instance.myISY.debugOff(); 472 Thread.sleep(200); 473 instance.loadButtonNodeAddresses(); 474 instance.loadButtonNodeNames(); 475 instance.initGui(); 476 System.out.println(ca.bc.webarts.tools.isy.ISY99CLI.dumpIsyProductInfo(instance.myISY).toString()); 477 System.out.println("\n\n"); 478 } 479 else 480 { 481 // put up a dialog to say no device authentication 482 JOptionPane.showMessageDialog(null, "Still No Go.\nCould Not Find/Authenticate any UDI ISY-99 devices.\nGiving up.", 483 "Alert", JOptionPane.ERROR_MESSAGE); 484 } 485 } 486 487 // hang tight until the window closes 488 while (instance.stillRunning_ ) 489 { 490 UDUtil.sleep(500); 491 } 492 } 493 catch (Exception e) 494 { 495 e.printStackTrace(); 496 } 497 finally 498 { 499 instance.isyCleanup(); 500 } 501 System.exit(0); 502 } 503 504 505 /** Gets The Window Up **/ 506 private void initGui() 507 { 508 509 initWindowPanels(); 510 pack(); 511 setLocation( xPosition_, yPosition_ ); 512 setVisible( true ); 513 toFront(); 514 515 nodeWatcherThread_.start(); 516 517 } 518 519 520 /** 521 * Handles all the Actions originating from the Control Buttons. 522 * 523 * @param e The action event to handle 524 */ 525 public void actionPerformed( ActionEvent e ) 526 { 527 final String methodName = className_ + ": actionPerformed()"; 528 529 JButton pressedButton = (JButton)( e.getSource() ); 530 ImageIcon buttonIcon = (ImageIcon)pressedButton.getIcon(); 531 String command = ""; 532 int commandButtonNumber = 0; 533 534 if ( buttonIcon != null && !buttonIcon.getDescription().startsWith("On") && !buttonIcon.getDescription().startsWith("Off")) 535 { 536 command = buttonIcon.getDescription(); 537 //System.out.println("Action From: "+command); 538 if ( command.trim().equals( "Close " + className_ ) ) 539 { 540 isyCleanup(); 541 //System.exit( 0 ); 542 } 543 544 boolean dim = command.trim().startsWith("dim"); 545 boolean bright = command.trim().startsWith("bright"); 546 if (!lastDevice_.equals("") && ( dim || bright) ) 547 { 548 System.out.println(lastDevice_+" to "+(dim?"Dim":"Brighten") ); 549 System.out.println(" Device Status: "+getStatus(getNodeFromAddress(lastDevice_.replace(" ",".")))); 550 if (dim) 551 { 552 //myISY.dimDevice(lastDevice_); 553 myISY.dimDevice(lastDevice_.replace("."," ")); 554 } 555 else if (bright) 556 { 557 //myISY.brightenDevice(lastDevice_); 558 myISY.brightenDevice(lastDevice_.replace("."," ")); 559 } 560 } 561 } 562 else if ( buttonIcon != null && (buttonIcon.getDescription().startsWith("On") || buttonIcon.getDescription().startsWith("Off"))) 563 { 564 String deviceAddress = pressedButton.getToolTipText(); 565 String onOffCommand = ( onOffToggle_.getState() ? InsteonConstants.DEVICE_ON : InsteonConstants.DEVICE_OFF ); 566 567 System.out.print("Button Pressed: "+onOffCommand+" "+deviceAddress ); 568 { 569 UDNode n = getNodeFromAddress(deviceAddress.replace(" ",".")); 570 String deviceStatus = getStatus(n); 571 // System.out.println(" to turn "+(onOffToggle_.getState()?"On":"Off") ); 572 System.out.println(" to turn "+(deviceStatus.equals("0")?"On":"Off") ); 573 System.out.println(" Device Status: "+deviceStatus); 574 //processCommand( onOffCommand+" "+Util.tokenReplace(deviceAddress," ",".") ); 575 576 //if (onOffToggle_.getState()) 577 if (deviceStatus==null||deviceStatus.equals("0")) 578 { 579 //myISY.turnDeviceOn(deviceAddress); 580 myISY.turnDeviceOn(deviceAddress.replace("."," ")); 581 // Update the ImageIcon 582 pressedButton.setIcon(onIcon); 583 } 584 else 585 { 586 //myISY.turnDeviceOff(deviceAddress); 587 myISY.turnDeviceOff(deviceAddress.replace("."," ")); 588 // Update the ImageIcon 589 pressedButton.setIcon(offIcon); 590 } 591 lastDevice_ = deviceAddress; 592 593 // Update the ImageIcon 594 //deviceStatus = getStatus(n); 595 //if (deviceStatus!=null && !deviceStatus.equals("")) pressedButton.setIcon(deviceStatus.equals("0")?offIcon:onIcon); 596 } 597 } 598 } 599 600 601 /** 602 * Returns all <code>UDNode</code>s that are associated in the client. 603 * @return the Enumeration UDNode if found, null otherwise 604 */ 605 protected Enumeration <UDNode> getNodes()// throws com.universaldevices.client.NoDeviceException 606 { 607 Enumeration <UDNode> isyNodes = null; 608 try 609 { 610 isyNodes = myISY.getNodes().elements(); 611 } 612 catch (Exception ex) // probably com.universaldevices.client.NoDeviceException 613 { 614 // send empty 615 } 616 return isyNodes; 617 618 //return myISY.getNodes().elements(); 619 } 620 621 622 /** 623 * Returns all<code>UDNode</code>s that are associated in the client. 624 * @return the Enumeration <UDNode> if found, null otherwise 625 */ 626 protected Enumeration <UDNode> getMyNodes()// throws com.universaldevices.client.NoDeviceException 627 { 628 Enumeration <UDNode> isyNodes = null; 629 Vector <UDNode> myNodes =new Vector<UDNode>(); 630 631 try 632 { 633 isyNodes = myISY.getNodes().elements(); 634 UDNode node = null; 635 636 while ( isyNodes.hasMoreElements()) 637 { 638 node = (UDNode) isyNodes.nextElement(); 639 // System.out.println(" Check To Add "+node.address + ":" + node.name+" type="+node.typeReadable+" -->"+ !node.typeReadable.startsWith("00.")); 640 myNodes.add(node); 641 } 642 } 643 catch (Exception ex) // probably com.universaldevices.client.NoDeviceException 644 { 645 // send empty 646 } 647 return myNodes.elements(); 648 } 649 650 651 /** 652 * Returns all NON-ControlLinc or Non-SwitchLinc <code>UDNode</code>s that are associated in the client. 653 * @return the Enumeration <UDNode> if found, null otherwise 654 */ 655 protected Enumeration <UDNode> getMyControlableNodes()// throws com.universaldevices.client.NoDeviceException 656 { 657 Enumeration <UDNode> isyNodes = null; 658 Vector <UDNode> myNodes =new Vector<UDNode>(); 659 660 try 661 { 662 isyNodes = myISY.getNodes().elements(); 663 UDNode node = null; 664 665 while ( isyNodes.hasMoreElements()) 666 { 667 node = (UDNode) isyNodes.nextElement(); 668 //System.out.println(" Check To Add "+node.address + ":" + node.name+" type="+node.typeReadable+" -->"+ !node.typeReadable.startsWith("00.")); 669 if (!node.typeReadable.startsWith("00.00") && /* ContolLinc */ 670 !node.typeReadable.startsWith("00.05") && /* RemoteLinc */ 671 !node.typeReadable.startsWith("00.10") && /* RemoteLinc2 */ 672 !node.typeReadable.startsWith("01.09") && /* SwitchLinc */ 673 !node.typeReadable.startsWith("05.03") && /* thermostat */ 674 !node.typeReadable.startsWith("01.1B") && /* switch */ 675 !node.typeReadable.startsWith("03.15") && /* USB connection */ 676 !node.typeReadable.startsWith("10.01") && /* motion sensor */ 677 !node.typeReadable.startsWith("09.07") /* iMeter Solo */ 678 ) 679 myNodes.add(node); 680 681 if (node.typeReadable.startsWith("01.1B") && /* SwitchLinc */ 682 node.address.endsWith("1") ) /* only add the MAIN switch */ 683 myNodes.add(node); 684 685 686 } 687 } 688 catch (Exception ex) // probably com.universaldevices.client.NoDeviceException 689 { 690 // send empty 691 } 692 return myNodes.elements(); 693 } 694 695 696 /** 697 * Forks a thread and watches myIsy for updates to the nodes being watched. 698 **/ 699 private void watchMyNodes() 700 { 701 } 702 703 704 /** 705 * Counts all the NON-ContolLinc Nodes that the ISY is aware of. 706 * @return the number of NON-ContolLinc nodes that the ISY is aware of. 707 **/ 708 private int countMyNodes() 709 { 710 int retVal = 0; 711 try 712 { 713 Enumeration <UDNode> e = getMyNodes(); 714 UDNode node = null; 715 while ( e.hasMoreElements()) 716 { 717 node = e.nextElement(); 718 retVal++; 719 } 720 } 721 catch (Exception ex) 722 { 723 ex.printStackTrace(); 724 } 725 return retVal; 726 } 727 728 729 /** 730 * Counts all the NON-ContolLinc Responder Nodes that the ISY is aware of. 731 * @return the number of NON-ContolLinc Responder nodes that the ISY is aware of. 732 **/ 733 private int countMyControlableNodes() 734 { 735 int retVal = 0; 736 try 737 { 738 Enumeration <UDNode> e = getMyControlableNodes(); 739 UDNode node = null; 740 while ( e.hasMoreElements()) 741 { 742 node = e.nextElement(); 743 //if (node.isResponder()) 744 retVal++; 745 } 746 } 747 catch (Exception ex) 748 { 749 ex.printStackTrace(); 750 } 751 return retVal; 752 } 753 754 755 /** 756 * Puts all the Node Address at this ISY into the insteonAddresses_ array. 757 **/ 758 private void loadNodeAddresses() 759 { 760 try 761 { 762 int numNodes = countMyNodes(); 763 insteonAddresses_ = new String[numNodes]; 764 System.out.println("\nLoading "+numNodes+" Button Devices"); 765 int count = 0; 766 Enumeration <UDNode> e = getMyNodes(); 767 while (e.hasMoreElements()) 768 { 769 UDNode node = e.nextElement(); 770 insteonAddresses_[count++] = Util.tokenReplace(node.address," ","."); 771 System.out.println(" "+node.address + ":" + node.name+" type="+node.typeReadable); 772 } 773 numButtons_ = numNodes; 774 //controlButton_ = new JButton[numNodes]; 775 } 776 catch (Exception ex) 777 { 778 ex.printStackTrace(); 779 } 780 781 } 782 783 784 /** 785 * Puts all the Node Address that are responders at this ISY into the insteonResponderAddresses_ array so they can get assigned to buttons. 786 **/ 787 private void loadButtonNodeAddresses() 788 { 789 try 790 { 791 int numNodes = countMyControlableNodes(); 792 insteonResponderAddresses_ = new String[numNodes]; 793 System.out.println("\nLoading "+numNodes+" Button Devices"); 794 int count = 0; 795 Enumeration <UDNode> e = getMyControlableNodes(); 796 while (e.hasMoreElements()) 797 { 798 UDNode node = e.nextElement(); 799 insteonResponderAddresses_[count++] = Util.tokenReplace(node.address," ","."); 800 System.out.println(" "+node.address + ":" + node.name+" type="+node.typeReadable); 801 } 802 numButtons_ = numNodes; 803 if (controlButton_==null) 804 controlButton_ = new JButton[numNodes]; 805 } 806 catch (Exception ex) 807 { 808 ex.printStackTrace(); 809 } 810 811 } 812 813 814 /** 815 * Puts all the Node Names that are responders at this ISY into the insteonResponderNamees_ array so they can get assigned to buttons. 816 **/ 817 private void loadButtonNodeNames() 818 { 819 try 820 { 821 int numNodes = countMyControlableNodes(); 822 insteonResponderNames_ = new String[numNodes]; 823 System.out.println("\nLoading "+numNodes+" Button Devices"); 824 int count = 0; 825 Enumeration <UDNode> e = getMyControlableNodes(); 826 while (e.hasMoreElements()) 827 { 828 UDNode node = e.nextElement(); 829 insteonResponderNames_[count++] = node.name; 830 //System.out.println(" "+node.address + ":" + node.name+" type="+node.typeReadable); 831 } 832 numButtons_ = numNodes; 833 if (controlButton_==null) 834 controlButton_ = new JButton[numNodes]; 835 } 836 catch (Exception ex) 837 { 838 ex.printStackTrace(); 839 } 840 841 } 842 843 844 /** 845 * Returns the current value of Insteon Devicse (its state) 846 * @param tk - the StringTokenzier 847 */ 848 protected void processStatus(StringTokenizer tk) 849 { 850 String tmp = tk.nextToken(); //device address 851 UDNode node = getNodeFromAddress(tmp); 852 if (node == null) 853 { 854 return; 855 } 856 857 tmp = (String) myISY.getCurrValue(node, InsteonConstants.DEVICE_STATUS); 858 System.out.println("The current status for " + node.address + "/" + node.name + " is " + tmp); 859 } 860 861 862 /** 863 * Returns the current value of an Insteon Device (its state) 864 * @param node - the UDNode to query 865 * @return the status 866 **/ 867 protected String getStatus(UDNode node ) 868 { 869 if (node == null) 870 { 871 return ""; 872 } 873 874 String tmp = (String) myISY.getCurrValue(node, InsteonConstants.DEVICE_STATUS); 875 //stem.out.println("The current status for " + node.address + "/" + node.name + " is " + tmp); 876 877 return tmp; 878 } 879 880 /** Duh! 881 * @param the node's address to query. 882 * @return the name assigned to the node at the address requested. 883 **/ 884 protected String getNodeNameFromAddress(String address) 885 { 886 if (address == null) 887 { 888 System.err.println("Missing Device/Scene address"); 889 return ""; 890 } 891 UDNode node = getNodeFromAddress(address); 892 return node.name; 893 } 894 895 896 /** 897 * Returns a <code>UDGroup</code> or a <code>UDNode</code> based on the 898 * given address 899 * @param address - the address of the node/scene to be retrieved 900 * @return the UDNode if found, null otherwise 901 */ 902 protected UDNode getNodeFromAddress(String address) 903 { 904 if (address == null) 905 { 906 System.err.println("Missing Device/Scene address"); 907 return null; 908 } 909 if (address.indexOf(".") > 0) 910 { 911 //this is an insteon device 912 address = address.replace(".", " "); //normalize it to our format 913 try 914 { 915 UDNode node = myISY.getNodes().get(address); 916 if (node == null) 917 { 918 System.err.println(" Address points to a non existing Insteon Device"); 919 return null; 920 } 921 return node; 922 } 923 catch (NoDeviceException e) 924 { 925 System.out.println(e); 926 return null; 927 } 928 } 929 930 //this is an insteon scene 931 try 932 { 933 UDGroup group = myISY.getGroups().get(address); 934 if (group == null) 935 { 936 System.err.println("Address points to a non-existing scene"); 937 return null; 938 } 939 return group; 940 } 941 catch (Exception e) 942 { 943 System.err.println(e); 944 return null; 945 } 946 } 947 948 /** 949 * Returns a <code>UDGroup</code> or a <code>UDNode</code> based on the 950 * given name 951 * @param address - the address of the node/scene to be retrieved 952 * @return the UDNode if found, null otherwise 953 */ 954 protected UDNode getNode(String nodeName) 955 { 956 if (nodeName == null) 957 { 958 System.err.println("Missing Device/Scene name"); 959 return null; 960 } 961 try 962 { 963 Enumeration <UDNode> isyNodes = null; 964 965 isyNodes = getNodes(); 966 UDNode node = null; 967 boolean notFound = true; 968 969 while (notFound && isyNodes.hasMoreElements()) 970 { 971 node = (UDNode) isyNodes.nextElement(); 972 if (nodeName.equals(node.name)) notFound = false; 973 } 974 975 if (node == null) 976 { 977 System.err.println("Address points to a non existing Insteon Device"); 978 return null; 979 } 980 return node; 981 } 982 catch (Exception e) 983 { 984 System.out.println(e); 985 return null; 986 } 987 } 988 989 protected char INSTEON_MASTER_MODE = 0xF0; 990 protected char INSTEON_SLAVE_MODE = 0x0F; 991 /** 992 * Returns the mode based on the input 993 * @param mode 994 * @return - the mode (INSTEON_MASTER_MODE, INSTEON_SLAVE_MODE) 995 **/ 996 protected char getMode(String mode) 997 { 998 if (mode.equals("M")) 999 { 1000 return INSTEON_MASTER_MODE; 1001 } 1002 1003 if (mode.equals("S")) 1004 { 1005 return INSTEON_SLAVE_MODE; 1006 } 1007 1008 System.err.println("Please specify M (for Master mode) or S (for Slave mode)"); 1009 return 0; 1010 } 1011 1012 /** 1013 * Processes an Insteon command 1014 * @param cmd - the command to be processed 1015 * @param tk - the StringTokenizer 1016 */ 1017 protected void processInsteonCommand(String cmd, StringTokenizer tk) 1018 { 1019 String address = tk.nextToken(); 1020 System.out.println("tk addr:"+address); 1021 UDNode node = getNodeFromAddress(address.replace(" ",".")); 1022 if (node == null) 1023 { 1024 return; 1025 } 1026 1027 //it's a group 1028 if (node instanceof UDGroup) 1029 { 1030 myISY.changeGroupState(cmd, null, node.address); 1031 } 1032 else 1033 { 1034 myISY.changeNodeState(cmd, null, node.address); 1035 } 1036 } 1037 1038 1039 /** 1040 * Abstracts the actual sending of the ISY Command. 1041 * 1042 * @param command This apps Command (not necessarily an Insteon Command (but could Be) 1043 */ 1044 public void processCommand( String command) 1045 { 1046 // Now disable all buttons and send the X10 command 1047 enableDeviceButtons( false ); 1048 1049 if (command == null || command.length() < 1) 1050 { 1051 return; 1052 } 1053 1054 System.out.println("Button Command:"+command); 1055 StringTokenizer tk = new StringTokenizer(command, " "); 1056 try 1057 { 1058 String cmd = tk.nextToken(); 1059 if ( cmd.startsWith(InsteonConstants.DEVICE_ON) || 1060 cmd.startsWith(InsteonConstants.DEVICE_OFF) || 1061 cmd.startsWith(InsteonConstants.DEVICE_FAST_ON) || 1062 cmd.startsWith(InsteonConstants.DEVICE_FAST_OFF) || 1063 cmd.startsWith(InsteonConstants.LIGHT_DIM) || 1064 cmd.startsWith(InsteonConstants.LIGHT_BRIGHT)) 1065 { 1066 System.out.println("Processing Cmd:"+cmd+" tk:"+tk.toString()); 1067 processInsteonCommand(cmd, tk); 1068 } 1069 else if (cmd.equalsIgnoreCase("StartLinking")) 1070 { 1071 myISY.startLinking(); 1072 } 1073 else if (cmd.equalsIgnoreCase("StopLinking")) 1074 { 1075 myISY.stopLinking(); 1076 } 1077 else if (cmd.startsWith("SetLinkingMode")) 1078 { 1079 //setLinkingMode(tk); 1080 } 1081 else if (cmd.startsWith("Rename")) 1082 { 1083 //processRename(tk); 1084 } 1085 else if (cmd.startsWith("Delete")) 1086 { 1087 // processDelete(tk); 1088 } 1089 else if (cmd.startsWith("Remove")) 1090 { 1091 //processRemoveFromScene(tk); 1092 } 1093 else if (cmd.startsWith("Move")) 1094 { 1095 // processMove(tk); 1096 } 1097 else if (cmd.startsWith("NewScene")) 1098 { 1099 // processNewScene(tk); 1100 } 1101 else if (cmd.startsWith("SetSceneOnLevel")) 1102 { 1103 //processSceneOnLevel(tk); 1104 } 1105 else if (cmd.startsWith("SetSceneRampRate")) 1106 { 1107 // processSceneRampRate(tk); 1108 } 1109 else if (cmd.startsWith("SetSceneControllerOnLevel")) 1110 { 1111 // processSceneControllerOnLevel(tk); 1112 } 1113 else if (cmd.startsWith("SetSceneControllerRampRate")) 1114 { 1115 //processSceneControllerRampRate(tk); 1116 } 1117 else if (cmd.equalsIgnoreCase("ListNodes")) 1118 { 1119 // processListNodes(); 1120 } 1121 else if (cmd.equalsIgnoreCase("ListScenes")) 1122 { 1123 // processListScenes(); 1124 } 1125 else if (cmd.startsWith("GetStatus")) 1126 { 1127 //processStatus(tk); 1128 } 1129 else if (cmd.equalsIgnoreCase("Exit")) 1130 { 1131 isyCleanup(); 1132 //System.exit(0); 1133 } 1134 else 1135 { 1136 syntaxError(); 1137 } 1138 } // try 1139 catch (Exception e) 1140 { 1141 e.printStackTrace(); 1142 syntaxError(); 1143 } 1144 //Util.sleep(2500); 1145 enableDeviceButtons( true ); 1146 } 1147 1148 1149 /** 1150 * Creates a text button using the node name as the button text, and the node's address as the toolTipText. 1151 * 1152 * @param controlAddress is the address of the Insteon Device to set this button up for. 1153 * @return A Button 1154 */ 1155 private JButton createButtonFromName( String controlName ) 1156 { 1157 ImageIcon onIcon = new ImageIcon( Util.loadImage( "/images/org/javalobby/icons/20x20/BulbOn.gif" ), "On " + className_ ); 1158 ImageIcon offIcon = new ImageIcon( Util.loadImage( "/images/org/javalobby/icons/20x20/BulbOff.gif" ), "Off " + className_ ); 1159 String nodeAddress = getNode( controlName).address ; 1160 //String nodeName_trunc = 1161 JButton retVal = new JButton( controlName ); 1162 // TO_DO: Add a custom tooltip naming the device on the end of this num 1163 retVal.setToolTipText( nodeAddress ); 1164 String deviceStatus = getStatus(getNode(controlName)); 1165 if (deviceStatus!=null && !deviceStatus.equals("")) retVal.setIcon(deviceStatus.equals("0")?offIcon:onIcon); 1166 retVal.addActionListener( this ); 1167 retVal.setBorder( BorderFactory.createBevelBorder( 1168 BevelBorder.RAISED ) ); 1169 retVal.setFont( retVal.getFont().deriveFont(10.0f)); 1170 return retVal; 1171 } 1172 1173 1174 /** 1175 * Creates a text button using the node name as the button text, and the node's address as the toolTipText. 1176 * 1177 * @param controlAddress is the address of the Insteon Device to set this button up for. 1178 * @return A Button 1179 */ 1180 private JButton createButtonFromAddress( String controlAddress ) 1181 { 1182 String nodeName = getNodeNameFromAddress( controlAddress) ; 1183 //String nodeName_trunc = 1184 JButton retVal = new JButton( nodeName ); 1185 // TO_DO: Add a custom tooltip naming the device on the end of this num 1186 retVal.setToolTipText( controlAddress ); 1187 retVal.addActionListener( this ); 1188 retVal.setBorder( BorderFactory.createBevelBorder( 1189 BevelBorder.RAISED ) ); 1190 retVal.setFont( retVal.getFont().deriveFont(10.0f)); 1191 return retVal; 1192 } 1193 1194 1195 /** Inits the gui widgets - buttons, layouts, etc.**/ 1196 private void initWindowPanels() 1197 { 1198 /* 1199 * Init Window dressing 1200 */ 1201 String miniViewFilename = "/images/miniViewButtonImage.jpg"; 1202 String miniCloseFilename = "/images/miniCloseButtonImage.jpg"; 1203 String x10DimFilename = "/images/Down24.gif"; 1204 String x10BrightFilename = "/images/Up24.gif"; 1205 1206 // the dragabler title bar button 1207 miniDragButton.setMaximumSize( new Dimension( 100, 16 ) ); 1208 miniDragButton.setBorder( BorderFactory.createRaisedBevelBorder() ); 1209 miniDragButton.setBorderPainted( true ); 1210 miniDragButton.setDoubleBuffered( true ); 1211 miniDragButton.add( miniDragLabel ); 1212 miniDragButton.addMouseListener( miniViewMouseListener ); 1213 miniDragButton.addMouseMotionListener( dragMiniViewMotionListener ); 1214 miniDragButton.addMouseListener( popupListener_ ); 1215 1216 // the mini close button 1217 iconMiniClose_ = 1218 new ImageIcon( Util.loadImage( miniCloseFilename ), "Close " + className_ ); 1219 miniButtonClose_.addActionListener( this ); 1220 miniButtonClose_.setIcon( iconMiniClose_ ); 1221 miniButtonClose_.setToolTipText( "Close " + className_ ); 1222 miniButtonClose_.setPreferredSize( new Dimension( 16, 16 ) ); 1223 miniButtonClose_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) ); 1224 miniButtonClose_.setBorderPainted( false ); 1225 miniButtonClose_.setDoubleBuffered( true ); 1226 1227 // the mini Dim button 1228 iconDim_ = 1229 new ImageIcon( Util.loadImage( x10DimFilename ), "dim" ); 1230 dimButton_.addActionListener( this ); 1231 dimButton_.setIcon( iconDim_ ); 1232 dimButton_.setToolTipText( "dim" ); 1233 dimButton_.setPreferredSize( new Dimension( 16, 16 ) ); 1234 dimButton_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) ); 1235 dimButton_.setBorderPainted( false ); 1236 dimButton_.setDoubleBuffered( true ); 1237 1238 // the mini Dim button 1239 iconBright_ = 1240 new ImageIcon( Util.loadImage( x10BrightFilename ), "bright" ); 1241 brightButton_.addActionListener( this ); 1242 brightButton_.setIcon( iconBright_ ); 1243 brightButton_.setToolTipText( "bright" ); 1244 brightButton_.setPreferredSize( new Dimension( 16, 16 ) ); 1245 brightButton_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) ); 1246 brightButton_.setBorderPainted( false ); 1247 brightButton_.setDoubleBuffered( true ); 1248 1249 // the Title Area Panel 1250 miniViewWindowControlPanel.add( miniDragButton, BorderLayout.CENTER ); 1251 miniViewWindowControlPanel.add( miniButtonClose_, BorderLayout.EAST ); 1252 miniViewWindowControlPanel.setDoubleBuffered( true ); 1253 miniViewWindowControlPanel.addMouseListener( popupListener_ ); 1254 1255 // the Button Panel 1256 miniButtonPanel_.setLayout( new GridLayout( displayRows_, displayCols_, 1, 1 ) ); 1257 miniButtonPanel_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) ); 1258 miniButtonPanel_.addMouseListener( popupListener_ ); 1259 java.util.Arrays.sort(insteonResponderNames_); 1260 // Do all the NON-X10 ones first 1261 for ( int i = 0; i < numButtons_; i++ ) 1262 { 1263 if (!insteonResponderNames_[i].startsWith("A")) 1264 { 1265 controlButton_[i] = createButtonFromName( insteonResponderNames_[i] ); 1266 miniButtonPanel_.add( controlButton_[i] ); 1267 } 1268 } 1269 // go through again and add the X10 ones 1270 for ( int i = 0; i < numButtons_; i++ ) 1271 { 1272 if (insteonResponderNames_[i].startsWith("A")) 1273 { 1274 controlButton_[i] = createButtonFromName( insteonResponderNames_[i] ); 1275 miniButtonPanel_.add( controlButton_[i] ); 1276 } 1277 } 1278 1279 dimPanel_.setLayout( new GridLayout( 1, 2, 1, 1 ) ); 1280 dimPanel_.setBorder( new EmptyBorder( 0, 0, 0, 0 ) ); 1281 //houseSpinner_.setValue( houseCodes_[0] ); 1282 //onOffPanel_.add( houseSpinner_ ); 1283 //onOffPanel_.add( onOffToggle_ ); 1284 dimPanel_.add( brightButton_ ); 1285 dimPanel_.add( dimButton_ ); 1286 1287 // now stitch it all together 1288 dragableMiniViewPanel.setDoubleBuffered( true ); 1289 dragableMiniViewPanel.setLayout( new BorderLayout( 0, 0 ) ); 1290 dragableMiniViewPanel.add( miniViewWindowControlPanel, BorderLayout.NORTH ); 1291 dragableMiniViewPanel.add( miniButtonPanel_, BorderLayout.CENTER ); 1292 dragableMiniViewPanel.add( dimPanel_, BorderLayout.SOUTH ); 1293 getContentPane().add( dragableMiniViewPanel ); 1294 } 1295 1296 1297 /** 1298 * Description of the Method 1299 * 1300 * @param state Description of the Parameter 1301 */ 1302 private void enableDeviceButtons( boolean state ) 1303 { 1304 for ( int i = 0; i < numButtons_; i++ ) 1305 { 1306 controlButton_[i].setEnabled( state ); 1307 } 1308 } 1309} 1310