Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / client / Colonet.java @ 1310

History | View | Annotate | Download (38.7 KB)

1 32 gtress
import javax.swing.*;
2 320 gtress
import javax.swing.event.*;
3
import javax.imageio.*;
4 32 gtress
import java.awt.*;
5
import java.awt.image.*;
6
import java.awt.event.*;
7
import java.net.*;
8
import java.io.*;
9 427 gtress
import java.util.*;
10 32 gtress
11 320 gtress
/**
12 531 emarinel
* The Colonet Graphical User Interface Applet for use locally and over an internet connection.
13
* @author Gregory Tress
14 527 emarinel
*
15 531 emarinel
* To generate javadoc on this file or other java files, use javadoc *.java -d doc, where doc
16
* is the name of the folder into which the files should be written.
17 320 gtress
*/
18 671 gtress
public class Colonet extends JApplet implements ActionListener, MouseInputListener, KeyListener {
19 320 gtress
20 32 gtress
        // Connection
21 527 emarinel
        JTextField txtHost;
22
        JTextField txtPort;
23
        JButton btnConnect;
24 414 gtress
        JButton btnGetXBeeIDs;
25 32 gtress
        JLabel lblConnectionStatus;
26 527 emarinel
        JTextArea txtInfo;
27 32 gtress
        JPanel panelConnect;
28
        JPanel panelServerInterface;
29 527 emarinel
        Socket socket;
30
        DataUpdater dataUpdater;
31
32 32 gtress
        // Control
33
        JTabbedPane tabPaneControl;
34
        JPanel panelRobotControl;
35
        JPanel panelRobotDirection;
36 320 gtress
        JPanel panelRobotDirectionButtons;
37 32 gtress
        JPanel panelRobotCommands;
38
        JButton btnF, btnB, btnL, btnR, btnActivate;
39 320 gtress
        JLabel lblBattery;
40 428 gtress
        JLabel lblSelected;
41 333 gtress
        BatteryIcon batteryIcon;
42 320 gtress
        JPanel panelBattery;
43
        VectorController vectorController;
44
        BufferedImage imageVectorControl;
45 427 gtress
        JButton btnAssignID;
46 702 gtress
        JButton btnLocateStation;
47
        boolean setStation;
48
        ChargingStation station;
49 428 gtress
        boolean setWaypoint;
50 429 gtress
        int setWaypointID;
51 739 gtress
        JButton btnSetBounds;
52
        JButton btnClearBounds;
53
        RobotBoundary boundary;
54 428 gtress
        JButton btnCommand_MoveTo;
55 429 gtress
        JButton btnCommand_MoveAll;
56 320 gtress
        JButton btnCommand_StopTask;
57
        JButton btnCommand_ResumeTask;
58
        JButton btnCommand_ChargeNow;
59
        JButton btnCommand_StopCharging;
60 527 emarinel
61 32 gtress
        // Task Manager
62
        JPanel panelTaskManager;
63
        JScrollPane spTaskManager;
64
        JPanel panelTaskManagerControls;
65
        JPanel panelTaskManagerControlsPriority;
66
        DefaultListModel taskListModel;
67
        JList taskList;
68
        JButton btnAddTask;
69
        JButton btnRemoveTask;
70
        JButton btnMoveTaskUp;
71
        JButton btnMoveTaskDown;
72 320 gtress
        JButton btnUpdateTasks;
73
        TaskAddWindow taskAddWindow;
74 527 emarinel
75 585 gtress
        // Webcam
76 320 gtress
        WebcamPanel panelWebcam;
77 32 gtress
        GraphicsConfiguration gc;
78 320 gtress
        JTabbedPane tabPaneMain;
79 585 gtress
        WebcamLoader webcamLoader;
80
81
        // Robots
82 531 emarinel
        volatile int selectedBot;         //the user has selected this bot graphically
83 671 gtress
        volatile RobotList robotIcons;         //contains boundary shapes around bots for click detection
84 320 gtress
        volatile int[] xbeeID;
85 527 emarinel
86 501 gtress
        Colonet self = this;
87 549 gtress
        volatile ColonetServerInterface csi;
88 32 gtress
89
        public void init () {
90 701 gtress
                // Set the default look and feel
91
                String laf = ColonetConstants.LOOK_AND_FEEL;
92 531 emarinel
                try {
93
                        UIManager.setLookAndFeel(laf);
94
                } catch (UnsupportedLookAndFeelException exc) {
95
                        System.err.println ("Warning: UnsupportedLookAndFeel: " + laf);
96
                } catch (Exception exc) {
97
                        System.err.println ("Error loading " + laf + ": " + exc);
98
                }
99
100 32 gtress
                // We should invoke and wait to avoid browser display difficulties
101
                Runnable r = new Runnable() {
102
                        public void run() {
103
                                createAndShowGUI();
104
                        }
105
                };
106 531 emarinel
107 32 gtress
                try {
108
                        SwingUtilities.invokeAndWait(r);
109
                } catch (InterruptedException e) {
110
                        //Not really sure why we would be in this situation
111 320 gtress
                        System.out.println("InterruptedException in init: " + e);
112 32 gtress
                } catch (java.lang.reflect.InvocationTargetException e) {
113 320 gtress
                        //This could happen for various reasons if there is a problem in createAndShowGUI
114
                        e.printStackTrace();
115 32 gtress
                }
116
        }
117 527 emarinel
118 32 gtress
        public void destroy () {
119 633 emarinel
                if (csi != null) {
120
                        csi.disconnect();
121 570 gtress
                }
122 32 gtress
        }
123
124
        private synchronized void createAndShowGUI () {
125 585 gtress
                // Webcam
126 527 emarinel
                gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
127 320 gtress
                panelWebcam = new WebcamPanel();
128
                tabPaneMain = new JTabbedPane();
129 739 gtress
                tabPaneMain.setFont(new Font("arial", Font.PLAIN, 14));
130 320 gtress
                tabPaneMain.add(panelWebcam, "Webcam");
131 527 emarinel
132 585 gtress
                // Robots
133 428 gtress
                selectedBot = -1;
134 671 gtress
                robotIcons = new RobotList();
135 527 emarinel
136 32 gtress
                // Connection area
137
                txtInfo = new JTextArea();
138
                txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
139 470 gtress
                txtHost = new JTextField(this.getDocumentBase().getHost());
140 32 gtress
                txtHost.setBorder(BorderFactory.createTitledBorder("Host"));
141
                txtPort = new JTextField("10123");
142
                txtPort.setBorder(BorderFactory.createTitledBorder("Port"));
143
                btnConnect = new JButton("Connect");
144 555 emarinel
                btnConnect.setFont(new Font("arial", Font.BOLD, 16));
145 414 gtress
                btnGetXBeeIDs = new JButton("Get XBee IDs");
146 389 gtress
                getRootPane().setDefaultButton(btnConnect);
147 32 gtress
                lblConnectionStatus = new JLabel("Status: Offline");
148
                panelConnect = new JPanel();
149
                panelConnect.setLayout(new GridLayout(6,1));
150
                panelConnect.add(lblConnectionStatus);
151
                panelConnect.add(txtHost);
152
                panelConnect.add(txtPort);
153
                panelConnect.add(btnConnect);
154
                panelServerInterface = new JPanel();
155
                panelServerInterface.setLayout(new GridLayout(2,1));
156
                panelServerInterface.add(panelConnect);
157 585 gtress
                panelServerInterface.add(txtInfo);
158 527 emarinel
159 32 gtress
                // Robot direction panel
160
                panelRobotDirection = new JPanel();
161 320 gtress
                panelRobotDirectionButtons = new JPanel();
162 555 emarinel
163 739 gtress
                Font f = new Font(null, Font.PLAIN, 16);
164 555 emarinel
                btnF = new JButton("\u2191");
165
                btnF.setFont(f);
166
                btnB = new JButton("\u2193");
167
                btnB.setFont(f);
168
                btnL = new JButton("\u2190");
169
                btnL.setFont(f);
170
                btnR = new JButton("\u2192");
171
                btnR.setFont(f);
172
                btnActivate = new JButton("\u25A0");
173 710 gtress
                btnActivate.setFont(new Font(null, Font.BOLD, 24));
174 555 emarinel
175 320 gtress
                panelRobotDirectionButtons.setLayout(new GridLayout(1,5));
176
                panelRobotDirectionButtons.add(btnActivate);
177
                panelRobotDirectionButtons.add(btnF);
178
                panelRobotDirectionButtons.add(btnB);
179
                panelRobotDirectionButtons.add(btnL);
180
                panelRobotDirectionButtons.add(btnR);
181 527 emarinel
182 701 gtress
                imageVectorControl = gc.createCompatibleImage(ColonetConstants.VECTOR_CONTROLLER_WIDTH, ColonetConstants.VECTOR_CONTROLLER_HEIGHT);
183 638 gtress
                vectorController = new VectorController(imageVectorControl, self);
184 320 gtress
                panelRobotDirection.setLayout(new BorderLayout());
185 585 gtress
                panelRobotDirection.add(vectorController, BorderLayout.CENTER);
186 320 gtress
                panelRobotDirection.add(panelRobotDirectionButtons, BorderLayout.SOUTH);
187 527 emarinel
188 32 gtress
                // Robot Control and Commands
189
                panelRobotCommands = new JPanel();
190 739 gtress
                panelRobotCommands.setLayout(new GridLayout(6,2));
191 333 gtress
                // Battery subset
192 514 gtress
                batteryIcon = new BatteryIcon(0);
193 333 gtress
                lblBattery = new JLabel(batteryIcon);
194 428 gtress
                lblSelected = new JLabel("None");
195 664 gtress
                // Management subset
196 702 gtress
                setStation = false;
197 428 gtress
                setWaypoint = false;
198 429 gtress
                setWaypointID = -1;
199 427 gtress
                btnAssignID = new JButton("Assign ID");
200 739 gtress
                btnLocateStation = new JButton("Identify Station");
201
                boundary = new RobotBoundary();
202
                btnSetBounds = new JButton("Set Boundary");
203
                btnClearBounds = new JButton("Clear Boundary");
204
                // Control subset
205 428 gtress
                btnCommand_MoveTo = new JButton("Move to ...");
206 429 gtress
                btnCommand_MoveAll = new JButton("Move all ...");
207 320 gtress
                btnCommand_StopTask = new JButton("Stop Current Task");
208
                btnCommand_ResumeTask = new JButton("Resume Current Task");
209
                btnCommand_ChargeNow = new JButton("Recharge Now");
210
                btnCommand_StopCharging = new JButton("Stop Recharging");
211
                panelRobotCommands.add(new JLabel("Battery Level: "));
212
                panelRobotCommands.add(lblBattery);
213 428 gtress
                panelRobotCommands.add(new JLabel("Selected Icon: "));
214
                panelRobotCommands.add(lblSelected);
215 427 gtress
                panelRobotCommands.add(btnAssignID);
216 702 gtress
    panelRobotCommands.add(btnLocateStation);
217 739 gtress
                panelRobotCommands.add(btnCommand_ChargeNow);
218
                panelRobotCommands.add(btnCommand_StopCharging);
219 664 gtress
                panelRobotCommands.add(btnSetBounds);
220 682 gtress
    panelRobotCommands.add(btnClearBounds);
221 428 gtress
                panelRobotCommands.add(btnCommand_MoveTo);
222 429 gtress
                panelRobotCommands.add(btnCommand_MoveAll);
223 427 gtress
                //panelRobotCommands.add(btnCommand_StopTask);
224
                //panelRobotCommands.add(btnCommand_ResumeTask);
225 32 gtress
                panelRobotControl = new JPanel();
226
                panelRobotControl.setLayout(new GridLayout(2,1));
227
                panelRobotControl.add(panelRobotDirection);
228
                panelRobotControl.add(panelRobotCommands);
229 527 emarinel
230 32 gtress
                // Task Manager
231
                panelTaskManager = new JPanel();
232
                panelTaskManager.setLayout(new BorderLayout());
233
                taskListModel = new DefaultListModel();
234
                taskList = new JList(taskListModel);
235
                taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
236
                taskList.setSelectedIndex(0);
237
                spTaskManager = new JScrollPane(taskList);
238
                panelTaskManagerControls = new JPanel();
239 320 gtress
                panelTaskManagerControls.setLayout(new GridLayout(1,4));
240 32 gtress
                panelTaskManagerControlsPriority = new JPanel();
241
                panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2));
242
                btnAddTask = new JButton("Add...");
243
                btnRemoveTask = new JButton("Remove");
244
                btnMoveTaskUp = new JButton("^");
245
                btnMoveTaskDown = new JButton("v");
246 320 gtress
                btnUpdateTasks = new JButton("Update");
247 32 gtress
                panelTaskManagerControlsPriority.add(btnMoveTaskUp);
248
                panelTaskManagerControlsPriority.add(btnMoveTaskDown);
249
                panelTaskManagerControls.add(btnAddTask);
250
                panelTaskManagerControls.add(btnRemoveTask);
251 320 gtress
                panelTaskManagerControls.add(btnUpdateTasks);
252 32 gtress
                panelTaskManagerControls.add(panelTaskManagerControlsPriority);
253
                panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
254
                panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
255
                panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH);
256 320 gtress
                taskAddWindow = new TaskAddWindow();
257 527 emarinel
258 32 gtress
                // Main control mechanism
259
                tabPaneControl = new JTabbedPane(JTabbedPane.TOP);
260 739 gtress
                tabPaneControl.setFont(new Font("arial", Font.PLAIN, 14));
261 701 gtress
                tabPaneControl.setPreferredSize(new Dimension(ColonetConstants.VECTOR_CONTROLLER_WIDTH, 0));
262 32 gtress
                tabPaneControl.addTab("Connection", panelServerInterface);
263
                tabPaneControl.addTab("Robots", panelRobotControl);
264 514 gtress
                //tabPaneControl.addTab("Tasks", panelTaskManager);
265 527 emarinel
266 320 gtress
                // Put all elements in the ContentPane
267 32 gtress
                this.getContentPane().setLayout(new BorderLayout());
268 320 gtress
                this.getContentPane().add(tabPaneMain, BorderLayout.CENTER);
269 702 gtress
                this.getContentPane().add(tabPaneControl, BorderLayout.EAST);
270 32 gtress
                this.setVisible(true);
271 559 gtress
272
                // Disable components before connecting
273
                btnConnect.setText("Connect");
274 682 gtress
    lblConnectionStatus.setText("Status: Disconnected");
275 702 gtress
    setComponentsEnabled(false);
276 527 emarinel
277 320 gtress
                /* Add all listeners here */
278
                // Task Management
279 32 gtress
                btnAddTask.addActionListener(this);
280
                btnRemoveTask.addActionListener(this);
281
                btnMoveTaskUp.addActionListener(this);
282
                btnMoveTaskDown.addActionListener(this);
283 320 gtress
                btnUpdateTasks.addActionListener(this);
284
                // Robot Control
285
                btnF.addActionListener(this);
286
                btnB.addActionListener(this);
287
                btnL.addActionListener(this);
288
                btnR.addActionListener(this);
289
                btnF.addKeyListener(this);
290
                btnB.addKeyListener(this);
291
                btnL.addKeyListener(this);
292
                btnR.addKeyListener(this);
293
                btnActivate.addActionListener(this);
294
                btnActivate.addKeyListener(this);
295 428 gtress
                btnCommand_MoveTo.addActionListener(this);
296 429 gtress
                btnCommand_MoveAll.addActionListener(this);
297 320 gtress
                btnCommand_StopTask.addActionListener(this);
298
                btnCommand_ResumeTask.addActionListener(this);
299
                btnCommand_ChargeNow.addActionListener(this);
300
                btnCommand_StopCharging.addActionListener(this);
301
                // Other
302 32 gtress
                btnConnect.addActionListener(this);
303 414 gtress
                btnGetXBeeIDs.addActionListener(this);
304 427 gtress
                btnAssignID.addActionListener(this);
305 702 gtress
                btnLocateStation.addActionListener(this);
306 682 gtress
    btnSetBounds.addActionListener(this);
307
    btnClearBounds.addActionListener(this);
308 527 emarinel
                panelWebcam.addMouseListener(this);
309 670 gtress
                panelWebcam.addMouseMotionListener(this);
310 32 gtress
        }
311 638 gtress
312
        public ColonetServerInterface getCSI () {
313 739 gtress
          return csi;
314 638 gtress
        }
315 527 emarinel
316 428 gtress
        public void paint (Graphics g) {
317 531 emarinel
                super.paint(g);
318 428 gtress
        }
319 527 emarinel
320 429 gtress
        public void update (Graphics g) {
321 531 emarinel
                paint(g);
322 429 gtress
        }
323 527 emarinel
324
        /**
325 585 gtress
        * Gets the JTextArea used for displaying debugging information.
326 333 gtress
        *
327 585 gtress
        * @return the JTextArea where debugging information can be displayed.
328 527 emarinel
        */
329 585 gtress
        public JTextArea getInfoPanel () {
330
                return txtInfo;
331 320 gtress
        }
332 527 emarinel
333
        /**
334 333 gtress
        * Parses a String containing BOM matrix information.
335 531 emarinel
        * The ColonetServerInterface receives lines of the BOM matrix.        (For encoding
336
        * information, see the ColonetServerInterface documentation.)         The entire matrix is passed
337 527 emarinel
        * to the client when requested. This method takes a string of the form
338 333 gtress
        * "[command code] [command code] [number of robots] [data0] [data1] ..."
339 527 emarinel
        * with tokens separated by spaces and containing no brackets.
340 333 gtress
        * The [command code]s are predefined values identifying this String as a BOM data
341 527 emarinel
        * String, [number of robots] is an integer, and the values that follow are
342 531 emarinel
        * the sensor readings of the robots in order, starting with robot 0.        Only [number of robots]^2
343
        * data entries will be read.        The matrix values are saved locally until the next String is parsed.
344 333 gtress
        *
345 527 emarinel
        *
346 333 gtress
        * @param line the String containing BOM matrix information.
347
        * @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots]^2 data entries in the String
348
        */
349 320 gtress
        public void parseMatrix (String line) {
350 585 gtress
                txtInfo.setText("");
351 320 gtress
                String [] str = line.split(" ");
352
                int num = Integer.parseInt(str[2]);
353
                for (int i = 0; i < num; i++) {
354
                        for (int j = 0; j < num; j++) {
355
                                String next = str[3 + i*num + j];
356 531 emarinel
                                if (next.equals("-1")) {
357 585 gtress
                                        txtInfo.append("-");
358 531 emarinel
                                } else {
359 585 gtress
                                        txtInfo.append(next);
360 531 emarinel
                                }
361
362
                                if (j < num - 1) {
363 585 gtress
                                        txtInfo.append(" ");
364 531 emarinel
                                }
365 320 gtress
                        }
366 531 emarinel
367
                        if (i < num - 1) {
368 585 gtress
                                txtInfo.append("\n");
369 531 emarinel
                        }
370 136 gtress
                }
371 510 gtress
                repaint();
372 136 gtress
        }
373 527 emarinel
374 420 gtress
        public void connect () {
375 682 gtress
    if (csi != null)
376
      return;
377
    csi = new ColonetServerInterface(self);
378
    csi.connect(txtHost.getText(), txtPort.getText());
379
    if (!csi.isReady()) {
380
      csi = null;
381
      return;
382
    }
383
    webcamLoader = new WebcamLoader(self);
384
    dataUpdater = new DataUpdater();
385
    dataUpdater.start();
386
    webcamLoader.start();
387
    Runnable r = new Runnable() {
388
      public void run () {
389
        btnConnect.setText("Disconnect");
390
        lblConnectionStatus.setText("Status: Connected");
391 702 gtress
        setComponentsEnabled(true);
392 682 gtress
      }
393
    };
394
    SwingUtilities.invokeLater(r);
395 420 gtress
        }
396 527 emarinel
397 420 gtress
        public void disconnect () {
398 702 gtress
    try {
399
        dataUpdater.interrupt();
400
    } catch (Exception e) {
401
    }
402
    csi = null;
403 559 gtress
                Runnable r = new Runnable() {
404 702 gtress
      public void run () {
405
                    btnConnect.setText("Connect");
406
              lblConnectionStatus.setText("Status: Disconnected");
407
        setComponentsEnabled(false);
408 708 gtress
        boundary = null;
409
        station = null;
410 702 gtress
            }
411 559 gtress
                };
412
                SwingUtilities.invokeLater(r);
413 420 gtress
        }
414 702 gtress
415
        private void setComponentsEnabled (boolean enabled) {
416
    btnF.setEnabled(enabled);
417
    btnB.setEnabled(enabled);
418
    btnL.setEnabled(enabled);
419
    btnR.setEnabled(enabled);
420
    btnActivate.setEnabled(enabled);
421
    btnAssignID.setEnabled(enabled);
422
    btnLocateStation.setEnabled(enabled);
423
    btnSetBounds.setEnabled(enabled);
424
    btnClearBounds.setEnabled(enabled);
425 739 gtress
    btnCommand_ChargeNow.setEnabled(enabled);
426
    btnCommand_StopCharging.setEnabled(enabled);
427 702 gtress
    btnCommand_MoveTo.setEnabled(enabled);
428
    btnCommand_MoveAll.setEnabled(enabled);
429
        }
430 527 emarinel
431 333 gtress
        /**
432
        * Parses a String containing a task queue update.
433
        * Format is currently not specified.
434
        * This method currently does nothing.
435
        *
436
        * @param line the String containing task queue update information.
437
        */
438 320 gtress
        public void parseQueue (String line) {
439 585 gtress
440 320 gtress
        }
441 527 emarinel
442 333 gtress
        /**
443
        * Parses a String containing XBee ID values.
444 531 emarinel
        * The ColonetServerInterface receives Strings of XBee information.        (For encoding
445
        * information, see the ColonetServerInterface documentation.)         This method takes
446 333 gtress
        * a string of the form "[command code] [command code] [number of robots] [id0] [id1] ..."
447 527 emarinel
        * with tokens separated by spaces and containing no brackets.
448 333 gtress
        * The [command code]s are predefined values identifying this String as an XBee
449 527 emarinel
        * ID String, [number of robots] is an integer, and the values that follow are
450 531 emarinel
        * the IDs of the robots in order, starting with robot 0.        Only [number of robots]
451
        * will be read.         The ID values are saved locally until the next String is parsed.
452 333 gtress
        * The purpose of having this list is to ensure that robots are properly identified for control purposes.
453 527 emarinel
        * This keeps robot identification consistent between sessions and prevents arbitrary assignment.
454 333 gtress
        *
455
        * @param line the String containing XBee ID information.
456
        * @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots] IDs in the String
457
        * @see ColonetServerInterface#sendXBeeIDRequest()
458
        */
459 320 gtress
        public void parseXBeeIDs (String line) {
460
                String [] str = line.split(" ");
461
                int num = Integer.parseInt(str[2]);
462
                xbeeID = new int[num];
463 531 emarinel
                for (int i = 0; i < num; i++) {
464 320 gtress
                        xbeeID[i] = Integer.parseInt(str[i+3]);
465 531 emarinel
                }
466 320 gtress
        }
467 527 emarinel
468 333 gtress
        /**
469
        * Parses a String containing battery information.
470 531 emarinel
        * The ColonetServerInterface receives Strings of battery information.         (For encoding
471
        * information, see the ColonetServerInterface documentation.)         This method takes
472 333 gtress
        * a string of the form "[command code] [command code] [robot ID] [value]"
473 527 emarinel
        * with tokens separated by spaces and containing no brackets.
474 333 gtress
        * The [command code]s are predefined values identifying this String as a battery
475
        * information String, [robot ID] is an integer, and [value] is a battery measurement.
476
        * This updates the batery information for a single robot.
477
        *
478 527 emarinel
        *
479 333 gtress
        * @param line the String containing battery information.
480
        * @see ColonetServerInterface#sendBatteryRequest(int)
481
        */
482 320 gtress
        public void parseBattery (String line) {
483 739 gtress
          int botNum, level;
484
          try {
485 625 gtress
                    String [] str = line.split(" ");
486
                    botNum = Integer.parseInt(str[2]);
487
                    level = Integer.parseInt(str[3]);
488
                } catch (NumberFormatException e) {
489
                    System.out.println("Could not parse battery update");
490
                    return;