Details | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 15 | arune | 1 | /* |
| 2 | * File created by Jimmy |
||
| 3 | * at 2003-sep-06 14:38:08 |
||
| 4 | */ |
||
| 5 | package Macbeth.Modules.modGenRoomControl; |
||
| 6 | |||
| 7 | import javax.swing.*; |
||
| 8 | import java.awt.*; |
||
| 9 | import java.awt.event.*; |
||
| 10 | import java.util.Iterator; |
||
| 11 | import java.util.HashMap; |
||
| 12 | |||
| 13 | import Macbeth.System.*; |
||
| 14 | import Macbeth.Utilities.UByte; |
||
| 15 | import Macbeth.Utilities.MySystem; |
||
| 16 | import Macbeth.Utilities.DataRepository; |
||
| 17 | import Macbeth.XML.XMLDataHandler; |
||
| 18 | |||
| 19 | /** |
||
| 20 | * A Macbeth module that allows the user to turn on/off |
||
| 21 | * lamps connected to the RoomControl ARNE node, which |
||
| 22 | * is assumed to be connected to the ARNE bus. The ARNE |
||
| 23 | * Macbeth module is required as well of course, or else |
||
| 24 | * this module won't be able to communicate with the |
||
| 25 | * RoomControl node. |
||
| 26 | * @author Jimmy, arune |
||
| 27 | * TODO: ska man testa om node-firendlyname existerar nar man laddar in dem? |
||
| 28 | */ |
||
| 29 | public class modGenRoomControl extends MbModule implements MbModuleGUI { |
||
| 30 | |||
| 31 | //A GUI for our module. |
||
| 32 | private GUI gui; |
||
| 33 | //Is our GUI currently visible or not? |
||
| 34 | private boolean guiVisible = false; |
||
| 35 | //A list of known room objects. |
||
| 36 | private HashMap roomObjects; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * Creates a new instance of modRoomControl. |
||
| 40 | */ |
||
| 41 | public modGenRoomControl() { |
||
| 42 | //construct MbModule |
||
| 43 | super(); |
||
| 44 | roomObjects = new HashMap(32); |
||
| 45 | gui = new GUI(); |
||
| 46 | //we depend on the RemoteControl-module |
||
| 47 | addDependency("RemoteControl"); |
||
| 48 | //we depend on the ARNE-module |
||
| 49 | addDependency("ARNE"); |
||
| 50 | //register our packet data handler |
||
| 51 | setPacketDataHandler(new PacketDataHandler()); |
||
| 52 | //we have a html-interface, so lets register it |
||
| 53 | setHTMLInterface(new HTMLInterface()); |
||
| 54 | } |
||
| 55 | |||
| 56 | /** |
||
| 57 | * Gets the name of the component. |
||
| 58 | * @return The name of the component. |
||
| 59 | */ |
||
| 60 | public String name() { |
||
| 61 | return "GenRoomControl"; |
||
| 62 | } |
||
| 63 | |||
| 64 | /** |
||
| 65 | * Gets the description of the component. |
||
| 66 | * @return The description of the component. |
||
| 67 | */ |
||
| 68 | public String description() { |
||
| 69 | return "Controls any on/off-thing via the ARNE bus"; |
||
| 70 | } |
||
| 71 | |||
| 72 | /** |
||
| 73 | * This method sets default values on all _required_ data |
||
| 74 | * fields in the data repository. |
||
| 75 | */ |
||
| 76 | protected void initDataFields() { |
||
| 77 | //this module doesn't require any data fields |
||
| 78 | } |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Starts up this module. |
||
| 82 | */ |
||
| 83 | public void startup() throws MbStartupException { |
||
| 84 | //start up MbModule |
||
| 85 | super.startup(); |
||
| 86 | |||
| 87 | //get all room objects from the data repository |
||
| 88 | DataRepository.DataList list = dataRepository.getList("roomobjects"); |
||
| 89 | if (list!=null) { |
||
| 90 | Iterator items = list.items(); |
||
| 91 | while (items.hasNext()) { |
||
| 92 | DataRepository.DataListItem item = (DataRepository.DataListItem)items.next(); |
||
| 93 | String name = (String)item.getField("name"); |
||
| 94 | String address = (String)item.getField("nodename"); |
||
| 95 | |||
| 96 | String bytes = (String)item.getField("byte"); |
||
| 97 | String[] bytearray = bytes.split(","); |
||
| 98 | UByte[] b = new UByte[bytearray.length]; |
||
| 99 | for (int i = 0; i < bytearray.length; i++) { |
||
| 100 | b[i] = UByte.parseUByte(bytearray[i]); |
||
| 101 | } |
||
| 102 | //UByte b = UByte.parseUByte((String)item.getField("byte")); |
||
| 103 | |||
| 104 | boolean pub = ((String)item.getField("public")).equals("true"); |
||
| 105 | String remotebtn = item.containsField("remotebutton") ? (String)item.getField("remotebutton") : ""; |
||
| 106 | roomObjects.put(name, new GenRoomObject(name, address, b, remotebtn, pub)); |
||
| 107 | } |
||
| 108 | } |
||
| 109 | //no room objects found in data repository |
||
| 110 | else { |
||
| 111 | _info.println("roomobjects-list is missing. no room objects defined!"); |
||
| 112 | } |
||
| 113 | |||
| 114 | //if we have any room objects |
||
| 115 | if (!roomObjects.isEmpty()) { |
||
| 116 | //lets send requests for their remote control buttons |
||
| 117 | MbPacket p = new MbPacket(); |
||
| 118 | p.setDestination(new MbLocation("self", "RemoteControl")); |
||
| 119 | Iterator it = roomObjects.keySet().iterator(); |
||
| 120 | while (it.hasNext()) { |
||
| 121 | String key = (String) it.next(); |
||
| 122 | GenRoomObject o = (GenRoomObject) roomObjects.get(key); |
||
| 123 | if (o != null) { |
||
| 124 | p.appendContents(" <buttonrequest button=\"" + o.remoteButton + "\" module=\"" + name() + "\" />"); |
||
| 125 | } |
||
| 126 | } |
||
| 127 | sendPacket(p); |
||
| 128 | } |
||
| 129 | } |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Shuts down this module. |
||
| 133 | */ |
||
| 134 | public void shutdown() { |
||
| 135 | //shut down MbModule |
||
| 136 | super.shutdown(); |
||
| 137 | } |
||
| 138 | |||
| 139 | /** |
||
| 140 | * A HTML-interface for this module. |
||
| 141 | */ |
||
| 142 | private class HTMLInterface implements MbHTMLInterface { |
||
| 143 | /** |
||
| 144 | * Retreives the full code for your HTML-page. This is |
||
| 145 | * formatted as plain text and must be valid HTML-code. |
||
| 146 | * @return Full HTML-code for the page. |
||
| 147 | * TODO: remove? redo? ta bort toggle? bor inte funkar alls om name anvamns |
||
| 148 | */ |
||
| 149 | public String getHTMLPage() { |
||
| 150 | String s = "<html><body>" + MySystem.lineBreak; |
||
| 151 | s += "<h1>Room Control module</h1>" + MySystem.lineBreak; |
||
| 152 | s += "<p>This module controls any on/off-node connected to ARNE bus.</p>" + MySystem.lineBreak; |
||
| 153 | s += "<h2>Controls:</h2>"; |
||
| 154 | s += "<center><p><table border=\"1\" cellpadding=\"3\" cellspacing=\"0\">"; |
||
| 155 | Iterator it = roomObjects.keySet().iterator(); |
||
| 156 | while (it.hasNext()) { |
||
| 157 | GenRoomObject o = (GenRoomObject)roomObjects.get(it.next()); |
||
| 158 | if (o!=null) { |
||
| 159 | if (o.displHTML) { //if display this object (configured in modGenRoomControl.xml) |
||
| 160 | s += "<tr><td>" + o.name + "</td><td>[<a href=\"toggle:" + o.name + "\">toggle</a>]</td><td>[<a href=\"on:" + o.name + "\">ON</a>]</td><td>[<a href=\"off:" + o.name + "\">OFF</a>]</td></tr></tr>"; |
||
| 161 | } |
||
| 162 | } |
||
| 163 | } |
||
| 164 | s += "</table></center>"; |
||
| 165 | s += "</body></html>"; |
||
| 166 | return s; |
||
| 167 | } |
||
| 168 | |||
| 169 | /** |
||
| 170 | * This method is invoked when a link is pressed on your |
||
| 171 | * HTML-page. |
||
| 172 | * @param href The href-attribute of the link. |
||
| 173 | */ |
||
| 174 | public void linkPressed(String href) { |
||
| 175 | String[] s = href.split(":"); |
||
| 176 | if (s.length >= 2) { |
||
| 177 | /* Ex: "toggle:Window lamp" |
||
| 178 | this means we should toggle the Window lamp. */ |
||
| 179 | if (s[0].equals("toggle")) { |
||
| 180 | GenRoomObject o = (GenRoomObject) roomObjects.get(s[1]); |
||
| 181 | if (o != null) { |
||
| 182 | toggleRoomObject(o.address, o.byteValue); |
||
| 183 | } |
||
| 184 | } |
||
| 185 | /* Ex: "on:Window lamp" |
||
| 186 | this means we should turn ON the Window lamp. */ |
||
| 187 | else if (s[0].equals("on")) { |
||
| 188 | GenRoomObject o = (GenRoomObject) roomObjects.get(s[1]); |
||
| 189 | if (o != null) { |
||
| 190 | setRoomObject(o.address, o.byteValue ,true); |
||
| 191 | } |
||
| 192 | } |
||
| 193 | /* Ex: "off:Window lamp" |
||
| 194 | this means we should turn OFF the Window lamp. */ |
||
| 195 | else if (s[0].equals("off")) { |
||
| 196 | GenRoomObject o = (GenRoomObject) roomObjects.get(s[1]); |
||
| 197 | if (o != null) { |
||
| 198 | setRoomObject(o.address, o.byteValue, false); |
||
| 199 | } |
||
| 200 | } |
||
| 201 | } |
||
| 202 | } |
||
| 203 | } |
||
| 204 | |||
| 205 | /** |
||
| 206 | * Takes care of XML-data found in incoming packets. |
||
| 207 | */ |
||
| 208 | private class PacketDataHandler implements XMLDataHandler { |
||
| 209 | /** |
||
| 210 | * Called when start of a new element is found in the XML-data. |
||
| 211 | * Ex: <name attr1="value1" attr2="value2"> |
||
| 212 | * Element name would then be "name" and attribute list |
||
| 213 | * would contain "value1" and "value2" mapped to the attribute |
||
| 214 | * names "attr1" and "attr2". |
||
| 215 | * @param element The name of the element. |
||
| 216 | * @param attributes The element attributes. |
||
| 217 | */ |
||
| 218 | public void XMLstartElement(String element, HashMap attributes) { |
||
| 219 | /** |
||
| 220 | * Ex: <remotecontrol button="NUMERIC4" state="DOWN" /> |
||
| 221 | * This is a notification from the remote control module |
||
| 222 | * about one of our requested remote control buttons have |
||
| 223 | * been pressed. |
||
| 224 | */ |
||
| 225 | if (element.equals("remotecontrol") && attributes.containsKey("button") && attributes.containsKey("state")) { |
||
| 226 | String state = (String)attributes.get("state"); |
||
| 227 | String button = (String)attributes.get("button"); |
||
| 228 | |||
| 229 | //find all room objects that are associated with this remote button |
||
| 230 | Iterator it = roomObjects.values().iterator(); |
||
| 231 | while (it.hasNext()) { |
||
| 232 | GenRoomObject o = (GenRoomObject)it.next(); |
||
| 233 | if (o.remoteButton.equals(button)) { |
||
| 234 | //toggle all such room objects |
||
| 235 | sendRoomObject(o.address, o.byteValue, state); |
||
| 236 | } |
||
| 237 | } |
||
| 238 | } |
||
| 239 | } |
||
| 240 | |||
| 241 | public void XMLendElement(String element) {} |
||
| 242 | public void XMLelementData(String data) {} |
||
| 243 | public void XMLdocumentStart() {} |
||
| 244 | public void XMLdocumentEnd() {} |
||
| 245 | } |
||
| 246 | |||
| 247 | /** |
||
| 248 | * |
||
| 249 | * @param address |
||
| 250 | * @param value |
||
| 251 | * @param state |
||
| 252 | */ |
||
| 253 | private void sendRoomObject(String address, UByte[] value, String state) { |
||
| 254 | int iState = 0; |
||
| 255 | |||
| 256 | if (state.equals("DOWN")) { |
||
| 257 | iState = 240; |
||
| 258 | } |
||
| 259 | else if (state.equals("UP")) { |
||
| 260 | iState = 0; |
||
| 261 | } |
||
| 262 | else if (state.equals("ON")) { |
||
| 263 | iState = 1; |
||
| 264 | } |
||
| 265 | else if (state.equals("OFF")) { |
||
| 266 | iState = 2; |
||
| 267 | } |
||
| 268 | |||
| 269 | //create a packet and address it to the ARNE module |
||
| 270 | MbPacket p = new MbPacket(); |
||
| 271 | p.setDestination(new MbLocation("self", "ARNE")); |
||
| 272 | //ARNE packet in XML-format |
||
| 273 | String contentValueData = ""; |
||
| 274 | for (int i = 0; i < value.length; i++) |
||
| 275 | { |
||
| 276 | contentValueData = contentValueData + "<byte id=\"" + (i+2) + "\" value=\"" + Integer.toString(value[i].shortValue()) + "\"/>"; |
||
| 277 | } |
||
| 278 | int arneBytes = value.length+1; |
||
| 279 | p.setContents("<arnepacket bytes=\"" + arneBytes + "\" destnode=\"" + address + "\">" + //destnode - address |
||
| 280 | "<byte id=\"1\" value=\"" + Integer.toString(iState) + "\"/>" + |
||
| 281 | contentValueData + |
||
| 282 | "</arnepacket>"); |
||
| 283 | sendPacket(p); |
||
| 284 | |||
| 285 | } |
||
| 286 | |||
| 287 | /** |
||
| 288 | * Toggles a room object (=lamp) by telling the RoomControl node |
||
| 289 | * to toggle a specific output. |
||
| 290 | * @param address |
||
| 291 | * @param value The object to toggle (0 is first one). |
||
| 292 | */ |
||
| 293 | private void toggleRoomObject(String address, UByte[] value) { |
||
| 294 | //create a packet and address it to the ARNE module |
||
| 295 | MbPacket p = new MbPacket(); |
||
| 296 | p.setDestination(new MbLocation("self", "ARNE")); |
||
| 297 | //ARNE packet in XML-format |
||
| 298 | String contentValueData = ""; |
||
| 299 | for (int i = 0; i < value.length; i++) |
||
| 300 | { |
||
| 301 | contentValueData = contentValueData + "<byte id=\"" + (i+2) + "\" value=\"" + Integer.toString(value[i].shortValue()) + "\"/>"; |
||
| 302 | } |
||
| 303 | int arneBytes = value.length+1; |
||
| 304 | p.setContents("<arnepacket bytes=\"" + arneBytes + "\" destnode=\"" + address +"\">" + |
||
| 305 | "<byte id=\"1\" value=\"240\"/>" + |
||
| 306 | contentValueData + |
||
| 307 | "</arnepacket>"); |
||
| 308 | sendPacket(p); |
||
| 309 | } |
||
| 310 | |||
| 311 | /** |
||
| 312 | * Sets the state of a room object (=lamp) by telling the RoomControl |
||
| 313 | * node either to turn on or to turn off the specified output. |
||
| 314 | * @param address |
||
| 315 | * @param value object whose state you want to set (0 is first one). |
||
| 316 | * @param state The new state of the object. ON=true, OFF=false. |
||
| 317 | */ |
||
| 318 | private void setRoomObject(String address, UByte[] value, boolean state) { |
||
| 319 | //create a packet and address it to the ARNE module |
||
| 320 | MbPacket p = new MbPacket(); |
||
| 321 | p.setDestination(new MbLocation("self", "ARNE")); |
||
| 322 | //ARNE packet in XML-format |
||
| 323 | String contentValueData = ""; |
||
| 324 | for (int i = 0; i < value.length; i++) |
||
| 325 | { |
||
| 326 | contentValueData = contentValueData + "<byte id=\"" + (i+2) + "\" value=\"" + Integer.toString(value[i].shortValue()) + "\"/>"; |
||
| 327 | } |
||
| 328 | int arneBytes = value.length+1; |
||
| 329 | p.setContents("<arnepacket bytes=\"" + arneBytes + "\" destnode=\"" + address + "\">" + |
||
| 330 | "<byte id=\"1\" value=\"" + (state==true ? "01" : "02") + "\"/>" + |
||
| 331 | contentValueData + |
||
| 332 | "</arnepacket>"); |
||
| 333 | sendPacket(p); |
||
| 334 | } |
||
| 335 | |||
| 336 | /** |
||
| 337 | * Will be called when our GUI should be shown. |
||
| 338 | */ |
||
| 339 | public void renderGUI(Container drawArea) { |
||
| 340 | gui.render(drawArea); |
||
| 341 | } |
||
| 342 | |||
| 343 | /** |
||
| 344 | * A class for our GUI. |
||
| 345 | */ |
||
| 346 | private class GUI implements ActionListener { |
||
| 347 | private JButton[] btnLampButtons; |
||
| 348 | |||
| 349 | public void render(Container renderArea) { |
||
| 350 | Iterator it = roomObjects.keySet().iterator(); |
||
| 351 | int i=0; |
||
| 352 | |||
| 353 | while (it.hasNext()) { |
||
| 354 | GenRoomObject o = (GenRoomObject)roomObjects.get(it.next()); |
||
| 355 | if (o!=null) { |
||
| 356 | if (o.displHTML) { |
||
| 357 | i++; |
||
| 358 | } |
||
| 359 | } |
||
| 360 | } |
||
| 361 | if (i > 0) { |
||
| 362 | renderArea.setLayout(new GridLayout(i, 1)); |
||
| 363 | btnLampButtons = new JButton[i]; |
||
| 364 | it = roomObjects.keySet().iterator(); |
||
| 365 | i=0; |
||
| 366 | while (it.hasNext()) { |
||
| 367 | GenRoomObject o = (GenRoomObject)roomObjects.get(it.next()); |
||
| 368 | if (o!=null) { |
||
| 369 | if (o.displHTML) { |
||
| 370 | btnLampButtons[i] = new JButton(o.name); |
||
| 371 | btnLampButtons[i].setActionCommand("roomobject:" + o.name); |
||
| 372 | btnLampButtons[i].addActionListener(this); |
||
| 373 | renderArea.add(btnLampButtons[i]); |
||
| 374 | i++; |
||
| 375 | } |
||
| 376 | } |
||
| 377 | } |
||
| 378 | } |
||
| 379 | } |
||
| 380 | |||
| 381 | public void actionPerformed(ActionEvent e) { |
||
| 382 | //was this a room object-button press? |
||
| 383 | if (e.getActionCommand().startsWith("roomobject:")) { |
||
| 384 | //split its actioncommand to find out which lamp it was for |
||
| 385 | String[] tokens = e.getActionCommand().split("roomobject:"); |
||
| 386 | //try to find a room object with this name |
||
| 387 | GenRoomObject o = (GenRoomObject)roomObjects.get(tokens[1]); |
||
| 388 | //if found |
||
| 389 | if (o!=null) { |
||
| 390 | //toggle corresponding room object |
||
| 391 | toggleRoomObject(o.address, o.byteValue); |
||
| 392 | } |
||
| 393 | } |
||
| 394 | } |
||
| 395 | } |
||
| 396 | } |