package com.homesnap.engine.connector.knxnetip; /* * #%L * HomeSnapEngine * %% * Copyright (C) 2011 - 2016 A. de Giuli * %% * This file is part of HomeSnap done by Arnaud de Giuli (arnaud.degiuli(at)free.fr) * helped by Olivier Driesbach (olivier.driesbach(at)gmail.com). * * HomeSnap 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. * * HomeSnap 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 HomeSnap. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.net.InetAddress; import java.net.NetworkInterface; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import tuwien.auto.calimero.exception.KNXException; import tuwien.auto.calimero.knxnetip.Discoverer; import tuwien.auto.calimero.knxnetip.servicetype.SearchResponse; import tuwien.auto.calimero.knxnetip.util.DeviceDIB; import tuwien.auto.calimero.knxnetip.util.HPAI; import tuwien.auto.calimero.link.medium.KNXMediumSettings; import tuwien.auto.calimero.link.medium.TPSettings; import com.homesnap.engine.connector.knxnetip.network.NetworkConfig; /** * * @author DRIESBACH Olivier * @version 1.0 * @since 1.0 */ public class KNXDiscoverer { /** */ private static KNXDiscoverer instance = new KNXDiscoverer(); /** */ private Map<InetAddress, KNXnetIPConnectionSettings> knxInetAddresses = new HashMap<InetAddress, KNXnetIPConnectionSettings>(); /** * */ private KNXDiscoverer() { } /** * * @return */ public static KNXDiscoverer getInstance() { return instance; } /** * * @return */ public Map<InetAddress, KNXnetIPConnectionSettings> findKNXNetIPAddresses() { return findKNXNetIPAddresses(false); } /** * * @param forceSearch * @return */ public Map<InetAddress, KNXnetIPConnectionSettings> findKNXNetIPAddresses(boolean forceSearch) { synchronized (knxInetAddresses) { if (knxInetAddresses.isEmpty() || forceSearch) { knxInetAddresses.clear(); // Clear previous results // Get all bindables inet addresses of this computer List<InetAddress> localAddresses = new ArrayList<InetAddress>(); for (InetAddress inetAddress : NetworkConfig.getInstance().getInetAdresses()) { if (!inetAddress.isLoopbackAddress()) { localAddresses.add(inetAddress); } } // Start a KNXDiscoveryWorker on each local IP address found List<KNXDiscoveryWorker> workers = new ArrayList<KNXDiscoveryWorker>(); for (InetAddress localAddress : localAddresses) { KNXDiscoveryWorker worker = new KNXDiscoveryWorker(localAddress); workers.add(worker); worker.start(); } // Wait the end of search of each worker in order to get all KNX NetIP devices found by IP address do { Iterator<KNXDiscoveryWorker> iter = workers.iterator(); while (iter.hasNext()) { KNXDiscoveryWorker worker = iter.next(); if (worker.isAlive()) { continue; } else { for (KNXnetIPConnectionSettings knxSettings : worker.getConnectionSettings()) { knxInetAddresses.put(knxSettings.getRemoteAddress(), knxSettings); } iter.remove(); } } if (!workers.isEmpty()) { try { Thread.sleep(1000); } catch (InterruptedException e) { } } } while (!workers.isEmpty()); } return Collections.unmodifiableMap(knxInetAddresses); } } /** * * @author DRIESBACH Olivier * @version 1.0 * @since 1.0 */ private class KNXDiscoveryWorker extends Thread { private InetAddress localAddress; private List<KNXnetIPConnectionSettings> connectionSettings; KNXDiscoveryWorker(InetAddress localAddress) { super("KNX discoverer on "+ localAddress.getHostName()); this.localAddress = localAddress; } public List<KNXnetIPConnectionSettings> getConnectionSettings() { return connectionSettings; } @Override public void run() { Discoverer knxDiscoverer = null; try { knxDiscoverer = new Discoverer(localAddress, 0, false); NetworkInterface networkInterface = NetworkConfig.getInstance().getInterface(localAddress); knxDiscoverer.startSearch(0, networkInterface, 3, false); System.out.println("Start searching KNXnetIP devices on "+ localAddress.getHostAddress() +" ("+ networkInterface.getDisplayName() +")"); while (knxDiscoverer.isSearching() && knxDiscoverer.getSearchResponses().length == 0) { try { Thread.sleep(500); } catch (Exception e) { } } } catch (KNXException e) { // TODO Log e.printStackTrace(); } connectionSettings = new ArrayList<KNXnetIPConnectionSettings>(); for (SearchResponse response : knxDiscoverer.getSearchResponses()) { HPAI endPoint = response.getControlEndpoint(); DeviceDIB netIPDevice = response.getDevice(); KNXMediumSettings knxSettings = null; switch (netIPDevice.getKNXMedium()) { case KNXMediumSettings.MEDIUM_TP0: case KNXMediumSettings.MEDIUM_TP1: { knxSettings = new TPSettings(netIPDevice.getAddress(), (KNXMediumSettings.MEDIUM_TP1 == netIPDevice.getKNXMedium())); break; } case KNXMediumSettings.MEDIUM_PL110: case KNXMediumSettings.MEDIUM_PL132: case KNXMediumSettings.MEDIUM_RF: { // TODO Log // throw new KNXException("KNX settings not yet supported"); } default: { // TODO Log // throw new KNXException("Unkwnon settings"); } } // if (log.isDebugEnabled()) { System.out.println("Found device : "+ netIPDevice.getName() +" (IP Address: "+ endPoint.getAddress() +", Address: "+ netIPDevice.getAddress() +", serial-number: "+ netIPDevice.getSerialNumberString() +", MAC Address: "+ netIPDevice.getMACAddressString() +")"); // } connectionSettings.add(new KNXnetIPConnectionSettings(localAddress, endPoint.getAddress(), endPoint.getPort(), knxSettings)); } } } }