/* * Dog - Network Driver * * Copyright 2013-2014 Davide Aimone and Dario Bonino * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package it.polito.elite.dog.drivers.zwave.network; import it.polito.elite.dog.core.library.model.ControllableDevice; import it.polito.elite.dog.core.library.util.LogHelper; import it.polito.elite.dog.drivers.zwave.ZWaveAPI; import it.polito.elite.dog.drivers.zwave.model.zway.json.Controller; import it.polito.elite.dog.drivers.zwave.model.zway.json.Device; import it.polito.elite.dog.drivers.zwave.model.zway.json.Instance; import it.polito.elite.dog.drivers.zwave.model.zway.json.ZWaveModelTree; import it.polito.elite.dog.drivers.zwave.network.info.ZWaveNodeInfo; import it.polito.elite.dog.drivers.zwave.network.interfaces.ZWaveNetwork; import it.polito.elite.dog.drivers.zwave.util.ConnessionManager; import java.util.Dictionary; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.Version; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; import org.osgi.service.log.LogService; public class ZWaveDriverImpl implements ZWaveNetwork, ManagedService { // the log identifier, unique for the class public static String LOG_ID = "[ZWaveDriverImpl]: "; // the bundle context private BundleContext bundleContext; // the service registration handle private ServiceRegistration<?> regServiceZWaveDriverImpl; // the driver logger private LogHelper logger; // connession maanger used to deal with zway server private ConnessionManager conManager; // model tree representing the system private ZWaveModelTree modelTree; // the register to driver map private ConcurrentHashMap<ZWaveNodeInfo, ZWaveDriverInstance> nodeInfo2Driver; // the inverse map private ConcurrentHashMap<ZWaveDriverInstance, Set<ZWaveNodeInfo>> driver2NodeInfo; // the zwave poller private ZWavePoller poller; // the baseline pollingTime adopted if no server-specific setting is given private int pollingTimeMillis = 5000; // default value private Version version; public ZWaveDriverImpl() { } @Override public void updated(Dictionary<String, ?> properties) throws ConfigurationException { // get the bundle configuration parameters if (properties != null) { logger.log(LogService.LOG_DEBUG, "Received configuration properties"); // Get credentials for connection String sUrl = (String) properties.get("loginUrl"); // try to get the baseline polling time String pollingTimeAsString = (String) properties .get("pollingTimeMillis"); // trim leading and trailing spaces pollingTimeAsString = pollingTimeAsString.trim(); // check not null if (pollingTimeAsString != null) { // parse the string pollingTimeMillis = Integer.valueOf(pollingTimeAsString); } // Get the connession manager and try to connect to the server conManager = ConnessionManager.get(sUrl, // sUsername, sPassword, bundleContext); // in any case, as the polling time has a default, init the poller // thread and start it poller = new ZWavePoller(this); // start the poller poller.start(); // log the driver start logger.log(LogService.LOG_INFO, ZWaveDriverImpl.LOG_ID + "Started the driver poller thread..."); // register the driver service if not already registered if (regServiceZWaveDriverImpl == null) regServiceZWaveDriverImpl = bundleContext.registerService( ZWaveNetwork.class.getName(), this, null); } } /** * Handle the bundle activation */ protected void activate(BundleContext bundleContext) { // create a logger logger = new LogHelper(bundleContext); // store the bundle context this.bundleContext = bundleContext; logger.log(LogService.LOG_DEBUG, "Activated: ZWave NetworkDriver..."); // create the register to driver map nodeInfo2Driver = new ConcurrentHashMap<ZWaveNodeInfo, ZWaveDriverInstance>(); // create the driver to register map driver2NodeInfo = new ConcurrentHashMap<ZWaveDriverInstance, Set<ZWaveNodeInfo>>(); } /** * Handle the bundle de-activation */ protected void deactivate() { // stop the poller if (poller != null) { poller.setRunnable(false); } // unregister service if (regServiceZWaveDriverImpl != null) regServiceZWaveDriverImpl.unregister(); } @Override public void read(ZWaveNodeInfo nodeInfo, boolean bRequery) { if (conManager != null) { try { // if needed update tree model if (bRequery || modelTree == null) modelTree = conManager.updateDevices(); Device deviceNode = null; Instance instanceNode = null; Controller controllerNode = null; // if node is the controller (gateway) we have to put also // controller data. if (nodeInfo.isController()) controllerNode = modelTree.getController(); deviceNode = modelTree.getDevices().get( nodeInfo.getDeviceNodeId()); Device device = modelTree.getDevices().get( nodeInfo.getDeviceNodeId()); // device can be null if house xml configuration is wrong if (device != null) { for (Integer instanceId : nodeInfo.getInstanceSet()) { instanceNode = device.getInstances().get(instanceId); // instance can be null if house xml configuration is // wrong if (instanceNode != null) { ZWaveDriverInstance driver = nodeInfo2Driver .get(nodeInfo); driver.newMessageFromHouse(deviceNode, instanceNode, controllerNode, null); } else { logger.log( LogService.LOG_ERROR, LOG_ID + "Device id: " + nodeInfo.getDeviceNodeId() + " instance id: " + instanceId + " does not exists!"); } } } else { logger.log(LogService.LOG_ERROR, LOG_ID + "Device id: " + nodeInfo.getDeviceNodeId() + " does not exists!"); } } catch (Exception e) { logger.log(LogService.LOG_ERROR, LOG_ID, e); e.printStackTrace(); } } } @Override public void readAll(boolean bRequery) { if (conManager != null) { try { // if needed update tree model if (bRequery || modelTree == null) modelTree = conManager.updateDevices(); // if version still not available if (this.version == null) { String versionAsString = (String) this.modelTree.getController() .getData().getAllData() .get("softwareRevisionVersion").getValue(); versionAsString = versionAsString.trim().substring(1); this.version = new Version(versionAsString); logger.log(LogService.LOG_INFO, "ZWay version:" + this.version); } for (Set<ZWaveNodeInfo> nodeInfos : driver2NodeInfo.values()) { for (ZWaveNodeInfo nodeInfo : nodeInfos) { read(nodeInfo, false); // yield to other processes Thread.yield(); } } } catch (Exception e) { logger.log(LogService.LOG_ERROR, LOG_ID, e); } } } @Override public void updateSensor(ZWaveNodeInfo nodeInfo) { // check if the node info is registered... if (this.nodeInfo2Driver.containsKey(nodeInfo)) { // send one update command per each command class for (Entry<Integer, Set<Integer>> instanceCC : nodeInfo .getInstanceSensorCC().entrySet()) { for (Integer ccToTrigger : instanceCC.getValue()) { try { // check if the model still contains the device: in some // cases device removal at the z-wave network-level may // happen before than the time in which the gateway // driver detects it. if (modelTree.getDevices().containsKey( nodeInfo.getDeviceNodeId())) { conManager.sendCommand("devices[" + nodeInfo.getDeviceNodeId() + "].instances[" + instanceCC.getKey() + "].commandClasses[" + ccToTrigger + "].Get()"); } } catch (Exception e) { logger.log(LogService.LOG_ERROR, LOG_ID + "Can't send command", e); } } } } } /* * (non-Javadoc) * * @see * it.polito.elite.dog.drivers.zwave.networkdriver.interfaces.ZWaveNetwork * #addDriver(it.polito.elite.dog.drivers.zwave.networkdriver.info. * ZWaveNodeInfo) */ @Override public void addDriver(ZWaveNodeInfo nodeInfo, int updateTimeMillis, ZWaveDriverInstance driver) { // get the register gateway address int deviceNodeId = nodeInfo.getDeviceNodeId(); Set<Integer> lstInstanceNodeId = nodeInfo.getInstanceSet(); // info on port usage logger.log(LogService.LOG_INFO, LOG_ID + "Using deviceId: " + deviceNodeId + " instancesId: " + lstInstanceNodeId.toString()); // adds a given register-driver association nodeInfo2Driver.put(nodeInfo, driver); // fills the reverse map Set<ZWaveNodeInfo> driverRegisters = driver2NodeInfo.get(driver); if (driverRegisters == null) { // create the new set of registers associated to the given driver driverRegisters = new HashSet<ZWaveNodeInfo>(); driver2NodeInfo.put(driver, driverRegisters); } driverRegisters.add(nodeInfo); // add a new device to the thread that is the responsible for device // update poller.addDeviceToQueue(nodeInfo, updateTimeMillis); } /* * (non-Javadoc) * * @see * it.polito.elite.dog.drivers.zwave.networkdriver.interfaces.ZWaveNetwork * #removeDriver(it.polito.elite.dog.drivers.zwave.networkdriver.info. * ZWaveNodeInfo) */ @Override public void removeDriver(ZWaveNodeInfo nodeInfo) { // removes a given register-driver association ZWaveDriverInstance drv = nodeInfo2Driver.remove(nodeInfo); if (drv != null) { driver2NodeInfo.remove(drv); } } @Override public void removeDriver(int nodeId) { ZWaveNodeInfo infoToRemove = null; // look for nodeinfos for (ZWaveNodeInfo info : this.nodeInfo2Driver.keySet()) { // compare the node id, if they are equal, get the driver and ask // for the device uri if (info.getDeviceNodeId() == nodeId) { infoToRemove = info; break; } } if (infoToRemove != null) { this.poller.removeDeviceFromQueue(nodeId); this.removeDriver(infoToRemove); } } /* * (non-Javadoc) * * @see * it.polito.elite.dog.drivers.zwave.networkdriver.interfaces.ZWaveNetwork * #removeDriver(it.polito.elite.dog.drivers.zwave.networkdriver.info. * ZWaveDriver) */ @Override public void removeDriver(ZWaveDriverInstance driver) { // removes a given driver-register association Set<ZWaveNodeInfo> driverNodeInfo = driver2NodeInfo.remove(driver); // remove the register-to-driver and the server-to-register associations if (driverNodeInfo != null) { for (ZWaveNodeInfo register : driverNodeInfo) { // remove the datapoint-to-driver associations nodeInfo2Driver.remove(register); } } } @Override public void write(int deviceId, int instanceId, int nCommandClass, String commandValue) { try { //version > 1.3.1 patch if(this.version.compareTo(new Version("1.3.1")) > 0) { if(nCommandClass == ZWaveAPI.GENERIC_TYPE_SWITCH_BINARY) { if(commandValue.equals("255")) commandValue = "true"; else commandValue = "false"; } } conManager.sendCommand("devices[" + deviceId + "].instances[" + instanceId + "].commandClasses[" + nCommandClass + "].Set(" + commandValue + ")"); } catch (Exception e) { logger.log(LogService.LOG_ERROR, LOG_ID + "Can't send command", e); } } @Override public void controllerWrite(String sCommand, String commandValue) { try { conManager.sendCommand(sCommand + "(" + commandValue + ")"); } catch (Exception e) { logger.log(LogService.LOG_ERROR, LOG_ID + "Can't send command", e); } } /** * Provides a reference to the {@link LogService} instance used by this * class to log messages... * * @return */ public LogHelper getLogger() { return logger; } /** * Provides the polling time to be used by Poller threads connect to this * driver instance... * * @return */ @Override public long getPollingTimeMillis() { return pollingTimeMillis; } /** * Get all devices currently available on the network, including devices * that still have to be configured in Dog */ @Override public Map<Integer, Device> getRawDevices() { return this.modelTree.getDevices(); } /** * Get raw device data on the basis of the given nodeId * * @return */ public Device getRawDevice(int nodeId) { return this.modelTree.getDevices().get(new Integer(nodeId)); } /** * checks among currently handled device whether the given node id exists, * and in the case, extracts the corresponding device URI * * @param nodeId * @return The URI of the corresponding {@link ControllableDevice} */ @Override public String getControllableDeviceURIFromNodeId(int nodeId) { String deviceId = null; // look for nodeinfos for (ZWaveNodeInfo info : this.nodeInfo2Driver.keySet()) { // compare the node id, if they are equal, get the driver and ask // for the device uri if (info.getDeviceNodeId() == nodeId) { // the driver currently connected to the device ZWaveDriverInstance driver = this.nodeInfo2Driver.get(info); // get the device uri deviceId = driver.getDevice().getDeviceId(); // break the cycle if the needed information has been found break; } } return deviceId; } }