Java tutorial
/** * Copyright (c) 2010-2015, openHAB.org and others. * * 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.lutron.internal; import java.io.IOException; import java.util.Dictionary; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.net.telnet.*; import org.openhab.binding.lutron.LutronBindingProvider; import org.openhab.core.binding.AbstractActiveBinding; import org.openhab.core.items.Item; import org.openhab.core.library.items.NumberItem; import org.openhab.core.library.items.StringItem; import org.openhab.core.library.items.SwitchItem; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.StringType; import org.openhab.core.transform.TransformationException; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The SNMP binding listens to SNMP Traps on the configured port and posts new * events of type ({@link StringType} to the event bus. * * @author Thomas.Eichstaedt-Engelen * @author Chris Jackson - modified binding to support polling SNMP OIDs (SNMP GET) and setting values (SNMP SET). * @since 0.9.0 */ public class LutronBinding extends AbstractActiveBinding<LutronBindingProvider> implements ManagedService { private abstract class LutronDevice implements Runnable, TelnetNotificationHandler { /** * */ public String IP; /** * */ public TelnetClient connection; /** * */ public LutronDevice() { // TODO implement here } /** * @param String IP */ public LutronDevice(String IP) { // TODO implement here } /** * @param int component */ public void enable(int component) { // TODO implement here } /** * @param int component */ public void disable(int component) { // TODO implement here } /** * @param int component */ public void press(int component) { // TODO implement here } /** * @param int component */ public void release(int component) { // TODO implement here } /** * @param int component */ public abstract void hold(int component); /** * @param int component */ public abstract void multiTap(int component); /** * @param int component * @param int scene */ public abstract void setScene(int component, int scene); /** * @param int component * @return */ public abstract int getScene(int component); /** * @param int component * @param int form */ public void setLED(int component, int form) { // TODO implement here } /** * @param int component * @return */ public Boolean getLED(int component) { // TODO implement here return null; } /** * @param int component * @param lock Boolean */ public abstract void setZoneLock(int component, Boolean lock); /** * @param int component * @return */ public abstract Boolean getZoneLock(int component); /** * @param int component * @param int lock */ public abstract void setSceneLock(int component, int lock); /** * @param int component * @return */ public abstract Boolean getSceneLock(int component); /** * @param int component * @param int scene */ public abstract void setSequenceState(int component, int scene); /** * @param int component * @return */ public abstract int getSequenceState(int component); /** * @param int component * @param Boolean isOutput */ public abstract void startRaising(int component, Boolean isOutput); /** * @param int component * @param Boolean isOutput */ public abstract void startLowering(int component, Boolean isOutput); /** * @param int component */ public abstract void stopRaisingLowering(int component); /** * @param int component * @return */ public int getBatteryStatus(int component) { // TODO implement here return 0; } /** * @param int component * @param int tilt * @param int lift */ public abstract void setLiftandTiltofBlinds(int component, int tilt, int lift); /** * @param int component * @param int lift */ public abstract void setLiftofBlinds(int component, int lift); /** * @param int component * @param int tilt */ public abstract void setTiltofBlinds(int component, int tilt); /** * @param int component */ public abstract void HoldRelease(int component); /** * @param int component * @param Boolean state */ public void setTimeClock(int component, Boolean state) { // TODO implement here } /** * @param int component * @return */ public Boolean getTimeClock(int component) { // TODO implement here return null; } /** * @param int component * @return */ public String getCCIState(int component) { // TODO implement here return ""; } /** * @param int component * @param String time */ public void startFlash(int component, String time) { // TODO implement here } /** * @param int component * @param String time */ public void startPulse(int component, String time) { // TODO implement here } /** * @param int component * @param float percentage * @param String fadeTime * @param String delayTime */ public abstract void setVenetianTiltLevel(int component, float percentage, String fadeTime, String delayTime); /** * @param int component * @return */ public abstract String[] getVenetianTiltLevel(int component); /** * @param int component * @param Float liftLevelPercentage * @param Float tiltLevelPercentage * @param String fadeTime * @param String delayTime */ public abstract void setVenetianTiltandLiftLevel(int component, Float liftLevelPercentage, Float tiltLevelPercentage, String fadeTime, String delayTime); /** * @param int component * @return */ public abstract String[] getVenetianTiltandLiftLevel(int component); /** * @param int component */ public abstract void startRaisingVenetianTilt(int component); /** * @param int component */ public abstract void startLoweringVenetianTilt(int component); /** * */ public abstract void stopVenetianTilt(); /** * @param int component */ public abstract void startRaisingVenetianLift(int component); /** * @param int component */ public abstract void startLoweringVenetianLift(int component); /** * @param int component */ public abstract void stopVenetianLift(int component); /** * @param int component * @param int color */ public abstract void setDMXColor(int component, int color); /** * @param int component * @param float level */ public abstract void setDMXLevel(int component, float level); /** * @param int component */ public abstract void motorJogRaise(int component); /** * @param int component */ public abstract void motorJogLower(int component); /** * @param int component */ public abstract void motor4StageJogRaise(int component); /** * @param int component */ public abstract void motor4StageJogLower(int component); /** * @param String command * @return */ public String[] sendCommand(String command) { // TODO implement here return null; } /** * @param int component * @param float level * @param String time1 * @param String time2 */ public abstract void setLightLevel(int component, float level, String time1, String time2); /** * @param int component * @return */ public abstract String[] getLightLevel(int component); /** * @param int component * @param float level * @param String time */ public void setZoneLevel(int component, Float level, String time) { // TODO implement here } /** * @param int component * @return */ public String[] getZoneLevel(int component) { // TODO implement here return null; } /** * @return */ public Boolean isConnectionAlive() { // TODO implement here return null; } @Override public void receivedNegotiation(int negotiation_code, int option_code) { // TODO Auto-generated method stub } @Override public void run() { // TODO Auto-generated method stub } } private class RadioRA2 extends LutronDevice { //This method is not implemented under RadioRA2 @Override public void hold(int component) { } //This method is not implemented under RadioRA2 @Override public void multiTap(int component) { } //This method is not implemented under RadioRA2 @Override public void setScene(int component, int scene) { } //This method is not implemented under RadioRA2 @Override public int getScene(int component) { return -1; } //This method is not implemented under RadioRA2 @Override public void setZoneLock(int component, Boolean lock) { } //This method is not implemented under RadioRA2 @Override public Boolean getZoneLock(int component) { return null; } //This method is not implemented under RadioRA2 @Override public void setSceneLock(int component, int lock) { } //This method is not implemented under RadioRA2 @Override public Boolean getSceneLock(int component) { return null; } //This method is not implemented under RadioRA2 @Override public void setSequenceState(int component, int scene) { } //This method is not implemented under RadioRA2 @Override public int getSequenceState(int component) { return 0; } @Override public void startRaising(int component, Boolean isOutput) { // TODO Implement } @Override public void startLowering(int component, Boolean isOutput) { // TODO Implement } @Override public void stopRaisingLowering(int component) { // TODO Implement } @Override public void setLiftandTiltofBlinds(int component, int tilt, int lift) { // TODO Implement } @Override public void setLiftofBlinds(int component, int lift) { // TODO Implement } @Override public void setTiltofBlinds(int component, int tilt) { // TODO Implement } //This method is not implemented under RadioRA2 @Override public void HoldRelease(int component) { } @Override public void setVenetianTiltLevel(int component, float percentage, String fadeTime, String delayTime) { // TODO implement } @Override public String[] getVenetianTiltLevel(int component) { // TODO implement return null; } @Override public void setVenetianTiltandLiftLevel(int component, Float liftLevelPercentage, Float tiltLevelPercentage, String fadeTime, String delayTime) { // TODO implement } @Override public String[] getVenetianTiltandLiftLevel(int component) { // TODO implement return null; } @Override public void startRaisingVenetianTilt(int component) { // TODO implement } @Override public void startLoweringVenetianTilt(int component) { // TODO implement } @Override public void stopVenetianTilt() { // TODO implement } @Override public void startRaisingVenetianLift(int component) { // TODO implement } @Override public void startLoweringVenetianLift(int component) { // TODO implement } @Override public void stopVenetianLift(int component) { // TODO implement } @Override public void setDMXColor(int component, int color) { // TODO implement } //This method is not implemented under RadioRA2 @Override public void setDMXLevel(int component, float level) { } //This method is not implemented under RadioRA2 @Override public void motorJogRaise(int component) { } //This method is not implemented under RadioRA @Override public void motorJogLower(int component) { } //This method is not implemented under RadioRA2 @Override public void motor4StageJogRaise(int component) { } //This method is not implemented under RadioRA2 @Override public void motor4StageJogLower(int component) { } @Override public void setLightLevel(int component, float level, String time1, String time2) { //TODO implement } @Override public String[] getLightLevel(int component) { return null; //TODO implement } } private static final Logger logger = LoggerFactory.getLogger(LutronBinding.class); private static DefaultUdpTransportMapping transport; private static final int LUTRON_DEFAULT_PORT = 162; /** The local port to bind on and listen to SNMP Traps */ private static int port = LUTRON_DEFAULT_PORT; /** The SNMP community to filter SNMP Traps */ private static String community; private static int timeout = 1500; private static int retries = 0; /** * the interval to find new refresh candidates (defaults to 1000 * milliseconds) */ private int granularity = 1000; private Map<String, Long> lastUpdateMap = new HashMap<String, Long>(); public void activate() { logger.debug("SNMP binding activated"); super.activate(); setProperlyConfigured(true); } public void deactivate() { stopListening(); logger.debug("SNMP binding deactivated"); } /** * @{inheritDoc */ @Override protected long getRefreshinterval() { return granularity; } /** * @{inheritDoc */ @Override protected String getName() { return "SNMP Refresh Service"; } /** * Configures a {@link DefaultUdpTransportMapping} and starts listening on * <code>SnmpBinding.port</code> for incoming SNMP Traps. */ private void listen() { UdpAddress address = new UdpAddress(LutronBinding.port); try { if (transport != null) { transport.close(); transport = null; } if (snmp != null) { snmp.close(); snmp = null; } transport = new DefaultUdpTransportMapping(address); // add all security protocols SecurityProtocols.getInstance().addDefaultProtocols(); SecurityProtocols.getInstance().addPrivacyProtocol(new Priv3DES()); // Create Target if (LutronBinding.community != null) { CommunityTarget target = new CommunityTarget(); target.setCommunity(new OctetString(LutronBinding.community)); } snmp = new Snmp(transport); transport.listen(); logger.debug("SNMP binding is listening on " + address); } catch (IOException ioe) { logger.error("SNMP binding couldn't listen to " + address, ioe); } } /** * Stops listening for incoming SNMP Traps */ private void stopListening() { if (transport != null) { try { transport.close(); } catch (IOException ioe) { logger.error("couldn't close connection", ioe); } transport = null; } if (snmp != null) { try { snmp.close(); } catch (IOException ioe) { logger.error("couldn't close snmp", ioe); } snmp = null; } } /** * Will be called whenever a {@link PDU} is received on the given port * specified in the listen() method. It extracts a {@link Variable} * according to the configured OID prefix and sends its value to the event * bus. */ public void processPdu(CommandResponderEvent event) { Address addr = event.getPeerAddress(); if (addr == null) { return; } String s = addr.toString().split("/")[0]; if (s == null) { logger.error("TRAP: failed to translate address {}", addr); dispatchPdu(addr, event.getPDU()); } else { // Need to change the port to 161, which is what the bindings are configured for since // at least some SNMP devices send traps from a random port number. Otherwise the trap // won't be found as the address check will fail. It feels like there should be a better // way to do this!!! Address address = GenericAddress.parse("udp:" + s + "/161"); dispatchPdu(address, event.getPDU()); } } /** * Called when a response from a GET is received * @see org.snmp4j.event.ResponseListener#onResponse(org.snmp4j.event.ResponseEvent ) */ @Override public void onResponse(ResponseEvent event) { dispatchPdu(event.getPeerAddress(), event.getResponse()); } private void dispatchPdu(Address address, PDU pdu) { if (pdu != null & address != null) { logger.debug("Received PDU from '{}' '{}'", address, pdu); for (LutronBindingProvider provider : providers) { for (String itemName : provider.getItemNames()) { // Check the IP address if (!provider.getAddress(itemName).equals(address)) { continue; } // Check the OID OID oid = provider.getOID(itemName); Variable variable = pdu.getVariable(oid); if (variable != null) { Class<? extends Item> itemType = provider.getItemType(itemName); // Do any transformations String value = variable.toString(); try { value = provider.doTransformation(itemName, value); } catch (TransformationException e) { logger.error("Transformation error with item {}: {}", itemName, e); } // Change to a state State state = null; if (itemType.isAssignableFrom(StringItem.class)) { state = StringType.valueOf(value); } else if (itemType.isAssignableFrom(NumberItem.class)) { state = DecimalType.valueOf(value); } else if (itemType.isAssignableFrom(SwitchItem.class)) { state = OnOffType.valueOf(value); } if (state != null) { eventPublisher.postUpdate(itemName, state); } else { logger.debug( "'{}' couldn't be parsed to a State. Valid State-Types are String and Number", variable.toString()); } } else { logger.trace("PDU doesn't contain a variable with OID {}", oid.toString()); } } } } } /** * @{inheritDoc */ @Override public void internalReceiveCommand(String itemName, Command command) { logger.debug("SNMP receive command {} from {}", itemName, command); LutronBindingProvider providerCmd = null; for (LutronBindingProvider provider : this.providers) { OID oid = provider.getOID(itemName, command); if (oid != null) { providerCmd = provider; break; } } if (providerCmd == null) { logger.warn("No match for binding provider [itemName={}, command={}]", itemName, command); return; } logger.debug("SNMP command for {} to {}", itemName, providerCmd.toString()); // Set up the target CommunityTarget target = new CommunityTarget(); target.setCommunity(providerCmd.getCommunity(itemName, command)); target.setAddress(providerCmd.getAddress(itemName, command)); target.setRetries(retries); target.setTimeout(timeout); target.setVersion(SnmpConstants.version1); Variable var = providerCmd.getValue(itemName, command); OID oid = providerCmd.getOID(itemName, command); VariableBinding varBind = new VariableBinding(oid, var); // Create the PDU PDU pdu = new PDU(); pdu.add(varBind); pdu.setType(PDU.SET); pdu.setRequestID(new integer32(1)); logger.debug("SNMP: Send CMD PDU {} {}", providerCmd.getAddress(itemName, command), pdu); if (snmp == null) { logger.error("SNMP: snmp not initialised - aborting request"); } else { sendPDU(target, pdu); } } /** * @{inheritDoc */ @Override public void execute() { for (LutronBindingProvider provider : providers) { for (String itemName : provider.getInBindingItemNames()) { int refreshinterval = provider.getRefreshinterval(itemName); Long lastUpdateTimeStamp = lastUpdateMap.get(itemName); if (lastUpdateTimeStamp == null) { lastUpdateTimeStamp = 0L; } long age = System.currentTimeMillis() - lastUpdateTimeStamp; Booleanean needsUpdate; if (refreshinterval == 0) { needsUpdate = false; } else { needsUpdate = age >= refreshinterval; } if (needsUpdate) { logger.debug("Item '{}' is about to be refreshed", itemName); // Set up the target CommunityTarget target = new CommunityTarget(); target.setCommunity(provider.getCommunity(itemName)); target.setAddress(provider.getAddress(itemName)); target.setRetries(retries); target.setTimeout(timeout); target.setVersion(SnmpConstants.version1); // Create the PDU PDU pdu = new PDU(); pdu.add(new VariableBinding(provider.getOID(itemName))); pdu.setType(PDU.GET); logger.debug("SNMP: Send PDU {} {}", provider.getAddress(itemName), pdu); if (snmp == null) { logger.error("SNMP: snmp not initialised - aborting request"); } else { sendPDU(target, pdu); } lastUpdateMap.put(itemName, System.currentTimeMillis()); } } } } /** * {@inheritDoc} */ public void updated(Dictionary<String, ?> config) throws ConfigurationException { Boolean mapping = false; stopListening(); if (config != null) { mapping = true; LutronBinding.community = (String) config.get("community"); if (StringUtils.isBlank(LutronBinding.community)) { LutronBinding.community = "public"; logger.info("didn't find SNMP community configuration -> listen to SNMP community {}", LutronBinding.community); } String portString = (String) config.get("port"); if (StringUtils.isNotBlank(portString) && portString.matches("\\d*")) { LutronBinding.port = integer.valueOf(portString).intValue(); } else { LutronBinding.port = LUTRON_DEFAULT_PORT; logger.info( "Didn't find SNMP port configuration or configuration is invalid -> listen to SNMP default port {}", LutronBinding.port); } String timeoutString = (String) config.get("timeout"); if (StringUtils.isNotBlank(timeoutString)) { LutronBinding.timeout = integer.valueOf(timeoutString).intValue(); if (LutronBinding.timeout < 0 | LutronBinding.retries > 5) { logger.info( "SNMP timeout value is invalid (" + LutronBinding.timeout + "). Using default value."); LutronBinding.timeout = 1500; } } else { LutronBinding.timeout = 1500; logger.info("Didn't find SNMP timeout or configuration is invalid -> timeout set to {}", LutronBinding.timeout); } String retriesString = (String) config.get("retries"); if (StringUtils.isNotBlank(retriesString)) { LutronBinding.retries = integer.valueOf(retriesString).intValue(); if (LutronBinding.retries < 0 | LutronBinding.retries > 5) { logger.info( "SNMP retries value is invalid (" + LutronBinding.retries + "). Using default value."); LutronBinding.retries = 0; } } else { LutronBinding.retries = 0; logger.info("Didn't find SNMP retries or configuration is invalid -> retries set to {}", LutronBinding.retries); } } for (LutronBindingProvider provider : providers) { if (provider.getInBindingItemNames() != null) { mapping = true; } } // Did we find either a trap request, or any bindings if (mapping) { listen(); } } private void sendPDU(CommunityTarget target, PDU pdu) { try { snmp.send(pdu, target, null, this); } catch (IOException e) { logger.error("Error sending PDU", e); } } @Override public void receivedNegotiation(int negotiation_code, int option_code) { // TODO Auto-generated method stub } @Override public void run() { // TODO Auto-generated method stub } @Override protected long getRefreshInterval() { // TODO Auto-generated method stub return 0; } }