2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.irobot.internal.dto;
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.net.DatagramPacket;
18 import java.net.DatagramSocket;
19 import java.net.InetAddress;
20 import java.nio.charset.StandardCharsets;
22 import com.google.gson.Gson;
23 import com.google.gson.JsonParseException;
24 import com.google.gson.stream.JsonReader;
27 * iRobot discovery and identification protocol
29 * @author Pavel Fedin - Initial contribution
32 public class IdentProtocol {
33 private static final String UDP_PACKET_CONTENTS = "irobotmcs";
34 private static final int REMOTE_UDP_PORT = 5678;
35 private static final Gson gson = new Gson();
37 public static DatagramSocket sendRequest(InetAddress host) throws IOException {
38 DatagramSocket socket = new DatagramSocket();
40 socket.setBroadcast(true);
41 socket.setReuseAddress(true);
43 byte[] packetContents = UDP_PACKET_CONTENTS.getBytes(StandardCharsets.UTF_8);
44 DatagramPacket packet = new DatagramPacket(packetContents, packetContents.length, host, REMOTE_UDP_PORT);
50 public static DatagramPacket receiveResponse(DatagramSocket socket) throws IOException {
51 byte[] buffer = new byte[1024];
52 DatagramPacket incomingPacket = new DatagramPacket(buffer, buffer.length);
54 socket.setSoTimeout(1000 /* one second */);
55 socket.receive(incomingPacket);
57 return incomingPacket;
60 public static IdentData decodeResponse(DatagramPacket packet) throws JsonParseException {
62 * packet is a JSON of the following contents (addresses are undisclosed):
66 * "hostname":"Roomba-3168820480607740",
67 * "robotname":"Roomba",
68 * "ip":"XXX.XXX.XXX.XXX",
69 * "mac":"XX:XX:XX:XX:XX:XX",
90 String reply = new String(packet.getData(), StandardCharsets.UTF_8);
91 // We are not consuming all the fields, so we have to create the reader explicitly
92 // If we use fromJson(String) or fromJson(java.util.reader), it will throw
93 // "JSON not fully consumed" exception, because not all the reader's content has been
94 // used up. We want to avoid that for compatibility reasons because newer iRobot versions
96 JsonReader jsonReader = new JsonReader(new StringReader(reply));
97 IdentData data = gson.fromJson(jsonReader, IdentData.class);
103 public static class IdentData {
104 public static int MIN_SUPPORTED_VERSION = 2;
105 public static String PRODUCT_ROOMBA = "Roomba";
108 private String hostname;
109 public String robotname;
111 // These two fields are synthetic, they are not contained in JSON
112 public String product;
115 public void postParse() {
116 // Synthesize missing properties.
117 String[] hostparts = hostname.split("-");
119 // This also comes from Roomba980-Python. Comments there say that "iRobot"
120 // prefix is used by i7. We assume for other robots it would be product
121 // name, e. g. "Scooba"
122 if (hostparts[0].equals("iRobot")) {
125 product = hostparts[0];