/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.zibase.internal; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openhab.core.events.EventPublisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.zapi.ZbResponse; import fr.zapi.Zibase; /** * Zibase Listener Thread class * * This class is used to connect to the zibase as a "listener" so it receive * every details about the zibase activity (RF orders, scenarios execution...). * Each supported activities is then sent on openHab bus as events. * * @author Julien Tiphaine * @since 1.7.0 * */ public class ZibaseListener extends Thread { /** * generic logger */ private static final Logger logger = LoggerFactory.getLogger(ZibaseBinding.class); /** * Regex pattern to extact X10 / Chacon RfId from zibase log */ private static final Pattern X10CHACONPATTERN = Pattern.compile(": ([A-Z][0-9]{1,2})(_)"); /** * Regex pattern to extact Radio ID from zibase log */ private static final Pattern RADIODIDPATTERM = Pattern.compile(": (<id>)([A-Z]{2}[0-9]*)"); /** * Regex pattern to extact Scenario id from zibase log */ private static final Pattern SCENARIOPATTERN = Pattern.compile(": ([0-9]{1,3})"); /** * zibase instance to listen to */ private Zibase zibase = null; /** * eventpubisher to publish update on */ private EventPublisher eventPubisher = null; /** * define wether the thread is running */ private boolean running = false; /** * ip address sent to Zibase for registering */ private String listenerHost = "127.0.0.1"; /** * ip address sent to Zibase for registering */ private int listenerPort = 9876; /** * Constructor */ public ZibaseListener() { logger.debug("Init ZibaseListener"); } /** * set zibase to listen to * * @param pZibase */ public void setZibase(Zibase pZibase) { this.zibase = pZibase; } /** * set host to send to zibase for registering * * @param pListenerHost */ public void setListenerHost(String pListenerHost) { this.listenerHost = pListenerHost; } /** * set host to send to zibase for registering * * @param pListenerPort */ public void setListenerPort(int pListenerPort) { this.listenerPort = pListenerPort; } /** * set eventpublisher to post update on * * @param pEventPublisher */ public void setEventPubisher(EventPublisher pEventPublisher) { this.eventPubisher = pEventPublisher; } /** * allow to shutdown the listener thread */ public void shutdown() { this.running = false; } /** * Thread main method. * register to the zibase system and start listening to every zibase messages */ @Override public void run() { if (zibase != null && eventPubisher != null) { try { // register to zibase for listening zibase.hostRegistering(listenerHost, listenerPort); DatagramSocket serverSocket = new DatagramSocket(listenerPort); // bind byte[] receiveData = new byte[470]; DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); running = true; // the real thread work is their : read message and analyse it to publish events on openhab bus while (running) { serverSocket.receive(receivePacket); ZbResponse zbResponse = new ZbResponse(receivePacket.getData()); logger.debug("ZIBASE MESSAGE: " + zbResponse.getMessage()); publishEvents(zbResponse); } zibase.hostUnregistering(listenerHost, listenerPort); } catch (SocketException ex) { logger.error("Could not open socket to zibase : " + ex); } catch (UnknownHostException ex) { logger.error("Given Zibase host not reachable : " + ex); } catch (IOException ex) { logger.error("IO eror reading Zibase socket : " + ex); } } else { logger.error("Zibase listener thread launched with no associated zibase and/or eventPublisher !"); } } /** * Get Item's id from zibase log * * @param zbResponseStr * @return */ protected String extractIdFromZbResponse(String zbResponseStr) { Matcher matcher = ZibaseListener.X10CHACONPATTERN.matcher(zbResponseStr); if (matcher.find()) { return matcher.group(1); } matcher = ZibaseListener.SCENARIOPATTERN.matcher(zbResponseStr); if (matcher.find()) { return matcher.group(1); } matcher = ZibaseListener.RADIODIDPATTERM.matcher(zbResponseStr); if (matcher.find()) { return matcher.group(2); } return null; } /** * publish configured zibase item messages on openhab bus * * @param zbResponse */ protected void publishEvents(ZbResponse zbResponse) { String zbResponseStr = zbResponse.getMessage(); String id = this.extractIdFromZbResponse(zbResponseStr); logger.debug("Found event from ID " + id); if (id == null) { return; } // ...retreive all itemNames that use this id... Vector<String> listOfItemNames = ZibaseBinding.getBindingProvider().getItemNamesById(id); if (listOfItemNames == null) { return; } logger.debug("trying to publish events for " + id); // then post update for all items that use this id for (String itemName : listOfItemNames) { ZibaseBindingConfig config = ZibaseBinding.getBindingProvider() .getItemConfigByUniqueId(itemName + "_" + id); logger.debug("Getting config for " + itemName + " (id = " + id + ") "); if (config != null) { org.openhab.core.types.State value = config.getOpenhabStateFromZibaseValue(zibase, zbResponseStr); logger.debug("publishing update for " + itemName + " : " + value); eventPubisher.postUpdate(itemName, value); } } } }