/** * 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.omnilink.internal; import java.io.IOException; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import org.apache.commons.lang.StringUtils; import org.openhab.binding.omnilink.OmniLinkBindingProvider; import org.openhab.binding.omnilink.internal.model.Area; import org.openhab.binding.omnilink.internal.model.AudioSource; import org.openhab.binding.omnilink.internal.model.AudioZone; import org.openhab.binding.omnilink.internal.model.Auxiliary; import org.openhab.binding.omnilink.internal.model.Button; import org.openhab.binding.omnilink.internal.model.OmnilinkDevice; import org.openhab.binding.omnilink.internal.model.Thermostat; import org.openhab.binding.omnilink.internal.model.Unit; import org.openhab.binding.omnilink.internal.model.Zone; import org.openhab.binding.omnilink.internal.ui.OmnilinkItemGenerator; import org.openhab.core.binding.AbstractBinding; import org.openhab.core.binding.BindingProvider; import org.openhab.core.items.Item; 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; import com.digitaldan.jomnilinkII.Connection; import com.digitaldan.jomnilinkII.DisconnectListener; import com.digitaldan.jomnilinkII.Message; import com.digitaldan.jomnilinkII.NotificationListener; import com.digitaldan.jomnilinkII.OmniInvalidResponseException; import com.digitaldan.jomnilinkII.OmniNotConnectedException; import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException; import com.digitaldan.jomnilinkII.MessageTypes.AudioSourceStatus; import com.digitaldan.jomnilinkII.MessageTypes.ObjectProperties; import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus; import com.digitaldan.jomnilinkII.MessageTypes.OtherEventNotifications; import com.digitaldan.jomnilinkII.MessageTypes.SystemStatus; import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties; import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioSourceProperties; import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioZoneProperties; import com.digitaldan.jomnilinkII.MessageTypes.properties.AuxSensorProperties; import com.digitaldan.jomnilinkII.MessageTypes.properties.ButtonProperties; import com.digitaldan.jomnilinkII.MessageTypes.properties.ThermostatProperties; import com.digitaldan.jomnilinkII.MessageTypes.properties.UnitProperties; import com.digitaldan.jomnilinkII.MessageTypes.properties.ZoneProperties; import com.digitaldan.jomnilinkII.MessageTypes.statuses.AreaStatus; import com.digitaldan.jomnilinkII.MessageTypes.statuses.AudioZoneStatus; import com.digitaldan.jomnilinkII.MessageTypes.statuses.AuxSensorStatus; import com.digitaldan.jomnilinkII.MessageTypes.statuses.Status; import com.digitaldan.jomnilinkII.MessageTypes.statuses.ThermostatStatus; import com.digitaldan.jomnilinkII.MessageTypes.statuses.UnitStatus; import com.digitaldan.jomnilinkII.MessageTypes.statuses.ZoneStatus; /** * Omnilink Binding allows full control over a HAI Omni or Lumina system * * @author Dan Cunningham * @since 1.5.0 */ public class OmniLinkBinding extends AbstractBinding<OmniLinkBindingProvider> implements ManagedService, NotificationListener { private static final Logger logger = LoggerFactory.getLogger(OmniLinkBinding.class); /* * the current OmniWorker thread */ private OmniConnectionThread omniWorker = null; /** * New items or items needing to be refreshed get added to refreshmao * the worker thread will refresh and remove them */ private Map<String, OmniLinkBindingConfig> refreshMap = Collections .synchronizedMap(new HashMap<String, OmniLinkBindingConfig>()); /** * we keep maps of the various object numbers to a specific object */ private Map<Integer, Area> areaMap = Collections.synchronizedMap(new HashMap<Integer, Area>()); private Map<Integer, AudioSource> audioSourceMap = Collections.synchronizedMap(new HashMap<Integer, AudioSource>()); private Map<Integer, AudioZone> audioZoneMap = Collections.synchronizedMap(new HashMap<Integer, AudioZone>()); private Map<Integer, Auxiliary> auxMap = Collections.synchronizedMap(new HashMap<Integer, Auxiliary>()); private Map<Integer, Thermostat> thermostatMap = Collections.synchronizedMap(new HashMap<Integer, Thermostat>()); private Map<Integer, Unit> unitMap = Collections.synchronizedMap(new HashMap<Integer, Unit>()); private Map<Integer, Zone> zoneMap = Collections.synchronizedMap(new HashMap<Integer, Zone>()); private Map<Integer, Button> buttonMap = Collections.synchronizedMap(new HashMap<Integer, Button>()); /** * We need to poll for audio source changes, that action * waits on this lock, if notified it will imediately * check for updates, useful of a zone is changing * tracks */ private Object audioUpdateLock = new Object(); public OmniLinkBinding() { } @Override public void activate() { logger.trace("OmniLinkBinding activate"); } @Override public void deactivate() { logger.debug("OmniLinkBinding disconnecting"); if (omniWorker != null) { omniWorker.setRunning(false); } } /** * {@inheritDoc} */ @Override public void bindingChanged(BindingProvider provider, String itemName) { if (provider instanceof OmniLinkBindingProvider) { OmniLinkBindingProvider omniProvider = (OmniLinkBindingProvider) provider; logger.debug("binding changed"); OmniLinkBindingConfig config = omniProvider.getOmniLinkBindingConfig(itemName); refreshMap.put(itemName, config); } } /** * {@inheritDoc} */ @Override public void allBindingsChanged(BindingProvider provider) { if (provider instanceof OmniLinkBindingProvider) { OmniLinkBindingProvider omniProvider = (OmniLinkBindingProvider) provider; populateRefreshMapFromProvider(omniProvider); logger.debug("all binding changed"); } } /** * @{inheritDoc */ @Override protected void internalReceiveCommand(String itemName, Command command) { // the code being executed when a command was sent on the openHAB // event bus goes here. This method is only called if one of the // BindingProviders provide a binding for the given 'itemName'. logger.debug("internalReceiveCommand() is called!!! {} {} ", itemName, command); if (omniWorker != null && omniWorker.isConnected()) { for (OmniLinkBindingProvider provider : providers) { OmniLinkBindingConfig config = provider.getOmniLinkBindingConfig(itemName); Item item = provider.getItem(itemName); List<OmniLinkControllerCommand> commands = OmniLinkCommandMapper.getCommand(item, config, command); /* * send each command we get back */ for (OmniLinkControllerCommand cmd : commands) { try { logger.debug("Sending command {}/{}/{}", new Object[] { cmd.getCommand(), cmd.getParameter1(), cmd.getParameter2() }); omniWorker.getOmniConnection().controllerCommand(cmd.getCommand(), cmd.getParameter1(), cmd.getParameter2()); // little hack to get audio updates faster. if (config.getObjectType() == OmniLinkItemType.AUDIOZONE_KEY) { audioUpdateLock.notifyAll(); } } catch (IOException e) { logger.error("Could not send command", e); } catch (OmniNotConnectedException e) { logger.error("Could not send command", e); } catch (OmniInvalidResponseException e) { logger.error("Could not send command", e); } catch (OmniUnknownMessageTypeException e) { logger.error("Could not send command", e); } } } } else { logger.debug("Could not send message, connection not established {}", omniWorker == null); } // get the } /** * @{inheritDoc */ @Override protected void internalReceiveUpdate(String itemName, State newState) { // the code being executed when a state was sent on the openHAB // event bus goes here. This method is only called if one of the // BindingProviders provide a binding for the given 'itemName'. logger.debug("internalReceiveCommand() is called! {} {}", itemName, newState); } protected void addBindingProvider(OmniLinkBindingProvider bindingProvider) { super.addBindingProvider(bindingProvider); } protected void removeBindingProvider(OmniLinkBindingProvider bindingProvider) { super.removeBindingProvider(bindingProvider); } /** * {@inheritDoc} */ @Override public void updated(Dictionary<String, ?> config) throws ConfigurationException { if (omniWorker != null) { omniWorker.setRunning(false); } if (config != null) { String host = (String) config.get("host"); int port = Integer.parseInt((String) config.get("port")); String key1 = (String) config.get("key1"); String key2 = (String) config.get("key2"); boolean generateItems = Boolean.parseBoolean((String) config.get("generateItems")); if (StringUtils.isEmpty(host) || StringUtils.isEmpty(key1) || StringUtils.isEmpty(key2)) { throw new ConfigurationException("omnilink", "host, key1 or key2 was not found"); } logger.debug("Starting update"); omniWorker = new OmniConnectionThread(host, port, key1 + ":" + key2, generateItems, this); omniWorker.start(); } } /** * Add items to be refreshed by our connection thread * * @param omniProvider */ private void populateRefreshMapFromProvider(OmniLinkBindingProvider omniProvider) { for (String itemName : omniProvider.getItemNames()) { OmniLinkBindingConfig config = omniProvider.getOmniLinkBindingConfig(itemName); refreshMap.put(itemName, config); } } /** * add items from all providers to be refreshed by our * connection thread */ private void populateRefreshMapFromAllProviders() { for (OmniLinkBindingProvider provider : providers) { populateRefreshMapFromProvider(provider); } } /** * This represents our internal connection thread, to stop set running = false * * @author daniel * */ private class OmniConnectionThread extends Thread { private boolean running = true; private boolean connected = false; private String host; private int port; private String key; private NotificationListener listener; private boolean celius; private boolean omni; private boolean generateItems; private Connection c; /** * This initializes, but does not start our main connection thread * * @param host * @param port * @param key * @param generateItems is if we should print a items list to the log * @param listener callback for events */ public OmniConnectionThread(String host, int port, String key, boolean generateItems, NotificationListener listener) { super("OmniConnectionThread"); this.host = host; this.port = port; this.key = key; this.listener = listener; this.generateItems = generateItems; this.running = false; // audioSources = new ConcurrentHashMap<Integer, AudioSource>(); logger.debug("OmniConnectionThread init"); } /* * is our thread running */ public boolean isRunning() { return running; } /* * Stop running and disconnect */ public void setRunning(boolean running) { this.running = running; if (!running) { audioUpdateLock.notifyAll(); } } /* * do we have a valid connection */ public boolean isConnected() { return connected; } /* * the connection object for sending commands */ public Connection getOmniConnection() { return c; } /** * Main processing loop */ @Override public void run() { running = true; logger.debug("OmniConnectionThread running"); while (running) { connected = false; /* * Connect to the system */ logger.debug("OmniConnectionThread trying to connect"); try { c = new Connection(host, port, key); connected = true; logger.debug("OmniConnectionThread connected"); } catch (Exception e) { logger.error("Could not connect", e); } /* * If we fail to connect sleep a bit before trying again */ if (!connected) { try { Thread.currentThread(); Thread.sleep(10 * 1000); } catch (InterruptedException ignored) { } } else { /* * If we get disconnected then do nothing */ c.addDisconnectListener(new DisconnectListener() { @Override public void notConnectedEvent(Exception e) { logger.error("OmniConnectionThread was disconnected, will try again", e); connected = false; } }); /* * Real time device changes get processed here */ c.addNotificationListener(listener); /* * Load everything and main audio source text loop */ try { SystemStatus sysstatus = c.reqSystemStatus(); logger.info("System: " + sysstatus.toString()); omni = c.reqSystemInformation().getModel() < 36; celius = c.reqSystemFormats().getTempFormat() > 1; /* * We need to explicitly tell the controller to send us * real time notifications */ c.enableNotifications(); if (generateItems) { try { OmnilinkItemGenerator gen = new OmnilinkItemGenerator(c); logger.info(gen.generateItemsAndGroups()); } catch (Exception e) { logger.error("Could not generate items", e); } } // update known items with state populateRefreshMapFromAllProviders(); // load audio sources, we won't get updates on these readAllAudioSources(); /* * if we get disconnected then refresh any devices that * we have to keep them up to date. */ while (running && c.connected()) { updateRefreshItems(); /* * Audio source text is not pushed in real time, so * we poll for it */ updateAudioSourceTexts(); try { synchronized (audioUpdateLock) { audioUpdateLock.wait(5000); } } catch (InterruptedException ignored) { } } } catch (IOException ex) { logger.error("Could not connect to system", ex); } catch (OmniNotConnectedException ex) { logger.error("Could not connect to system", ex.getNotConnectedReason()); } catch (OmniInvalidResponseException ex) { logger.error("Could not connect to system", ex); } catch (OmniUnknownMessageTypeException ex) { logger.error("Could not connect to system", ex); // is this needed? I just added this without looking at // the code for 2 years } catch (Exception ex) { logger.error("Could not connect to system", ex); } finally { c.disconnect(); c = null; } } } } /** * This goes through a map of item names and updates their state's * * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private void updateRefreshItems() throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { if (refreshMap.size() == 0) { return; } Map<String, OmniLinkBindingConfig> itemMap = new HashMap<String, OmniLinkBindingConfig>(refreshMap); for (String itemName : itemMap.keySet()) { OmniLinkBindingConfig config = itemMap.get(itemName); refreshMap.remove(itemName); if (config != null) { Integer number = new Integer(config.getNumber()); for (OmniLinkBindingProvider provider : providers) { switch (config.getObjectType()) { case UNIT: { UnitProperties p = readUnitProperties(config.getNumber()); Unit unit = unitMap.get(number); if (unit == null) { unit = new Unit(p); unitMap.put(number, unit); } config.setDevice(unit); unit.setProperties(p); unit.updateItem(provider.getItem(itemName), config, eventPublisher); } break; case THERMO_COOL_POINT: case THERMO_FAN_MODE: case THERMO_HEAT_POINT: case THERMO_HOLD_MODE: case THERMO_SYSTEM_MODE: case THERMO_TEMP: { ThermostatProperties p = readThermoProperties(config.getNumber()); Thermostat thermo = thermostatMap.get(number); if (thermo == null) { thermo = new Thermostat(p, celius); thermostatMap.put(number, thermo); } config.setDevice(thermo); thermo.setProperties(p); thermo.updateItem(provider.getItem(itemName), config, eventPublisher); } break; case AUDIOZONE_MUTE: case AUDIOZONE_POWER: case AUDIOZONE_SOURCE: case AUDIOZONE_KEY: case AUDIOZONE_TEXT: case AUDIOZONE_TEXT_FIELD1: case AUDIOZONE_TEXT_FIELD2: case AUDIOZONE_TEXT_FIELD3: case AUDIOZONE_VOLUME: { AudioZoneProperties p = readAudioZoneProperties(config.getNumber()); AudioZone audioZone = audioZoneMap.get(number); if (audioZone == null) { audioZone = new AudioZone(p); audioZone.setAudioSource(audioSourceMap); audioZoneMap.put(number, audioZone); } config.setDevice(audioZone); audioZone.setProperties(p); audioZone.updateItem(provider.getItem(itemName), config, eventPublisher); } break; case AUDIOSOURCE_TEXT: case AUDIOSOURCE_TEXT_FIELD1: case AUDIOSOURCE_TEXT_FIELD2: case AUDIOSOURCE_TEXT_FIELD3: { AudioSource as = audioSourceMap.get(number); if (as != null) { config.setDevice(as); as.updateItem(provider.getItem(itemName), config, eventPublisher); } } break; case AREA_ENTRY_TIMER: case AREA_EXIT_TIMER: case AREA_STATUS_ALARM: case AREA_STATUS_ENTRY_DELAY: case AREA_STATUS_EXIT_DELAY: case AREA_STATUS_MODE: { AreaProperties p = readAreaProperties(config.getNumber()); Area area = areaMap.get(number); if (area == null) { area = new Area(p, omni); areaMap.put(number, area); } config.setDevice(area); area.setProperties(p); area.updateItem(provider.getItem(itemName), config, eventPublisher); } break; case AUX_CURRENT: case AUX_HIGH: case AUX_LOW: case AUX_STATUS: { AuxSensorProperties p = readAuxProperties(config.getNumber()); Auxiliary auxiliary = auxMap.get(number); if (auxiliary == null) { auxiliary = new Auxiliary(p, celius); auxMap.put(number, auxiliary); } config.setDevice(auxiliary); auxiliary.setProperties(p); auxiliary.updateItem(provider.getItem(itemName), config, eventPublisher); } break; case ZONE_STATUS_ARMING: case ZONE_STATUS_CURRENT: case ZONE_STATUS_LATCHED: case ZONE_STATUS_ALL: { ZoneProperties p = readZoneProperties(config.getNumber()); Zone zone = zoneMap.get(number); if (zone == null) { zone = new Zone(p); zoneMap.put(number, zone); } config.setDevice(zone); zone.setProperties(p); zone.updateItem(provider.getItem(itemName), config, eventPublisher); } break; case BUTTON: { ButtonProperties p = readButtonProperties(config.getNumber()); Button button = buttonMap.get(number); if (button == null) { button = new Button(p); buttonMap.put(number, button); } config.setDevice(button); } break; default: break; } } } } } /** * Iterate through the system units (lights) * * @param number of the unti * @return UnitProperties of unit, null if not found * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private UnitProperties readUnitProperties(int number) throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Message m = c.reqObjectProperties(Message.OBJ_TYPE_UNIT, number, 0, ObjectProperties.FILTER_1_NAMED, ObjectProperties.FILTER_2_AREA_ALL, ObjectProperties.FILTER_3_ANY_LOAD); if (m.getMessageType() == Message.MESG_TYPE_OBJ_PROP) { return ((UnitProperties) m); } return null; } /** * Read the properties of a thermostat * * @param number of the thermostat * @return ThermostatProperties of thermostat or null if not found * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private ThermostatProperties readThermoProperties(int number) throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Message m = c.reqObjectProperties(Message.OBJ_TYPE_THERMO, number, 0, ObjectProperties.FILTER_1_NAMED, ObjectProperties.FILTER_2_AREA_ALL, ObjectProperties.FILTER_3_ANY_LOAD); if (m.getMessageType() == Message.MESG_TYPE_OBJ_PROP) { return ((ThermostatProperties) m); } return null; } /** * Read the properties of a Auxiliary sensor * * @param number of Auxiliary sensor * @return AuxSensorProperties of Auxiliary sensor or null if not found * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private AuxSensorProperties readAuxProperties(int number) throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Message m = c.reqObjectProperties(Message.OBJ_TYPE_AUX_SENSOR, number, 0, ObjectProperties.FILTER_1_NAMED, ObjectProperties.FILTER_2_AREA_ALL, ObjectProperties.FILTER_3_ANY_LOAD); if (m.getMessageType() == Message.MESG_TYPE_OBJ_PROP) { return ((AuxSensorProperties) m); } return null; } /** * Read the properties of a audio zone * * @param number of audio zone * @return AudioZoneProperties of audio zone, or null if not found * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private AudioZoneProperties readAudioZoneProperties(int number) throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Message m = c.reqObjectProperties(Message.OBJ_TYPE_AUDIO_ZONE, number, 0, ObjectProperties.FILTER_1_NAMED, ObjectProperties.FILTER_2_NONE, ObjectProperties.FILTER_3_NONE); if (m.getMessageType() == Message.MESG_TYPE_OBJ_PROP) { return ((AudioZoneProperties) m); } return null; } /** * Read the properties of a area * * @param number of area * @return AreaProperties of area or null if not found * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private AreaProperties readAreaProperties(int number) throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Message m = c.reqObjectProperties(Message.OBJ_TYPE_AREA, number, 0, ObjectProperties.FILTER_1_NAMED_UNAMED, ObjectProperties.FILTER_2_NONE, ObjectProperties.FILTER_3_NONE); if (m.getMessageType() == Message.MESG_TYPE_OBJ_PROP) { return ((AreaProperties) m); } return null; } /** * Read the properties of a zone * * @param number of zone * @return ZoneProperties of zone, or null if not found * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private ZoneProperties readZoneProperties(int number) throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Message m = c.reqObjectProperties(Message.OBJ_TYPE_ZONE, number, 0, ObjectProperties.FILTER_1_NAMED, ObjectProperties.FILTER_2_AREA_ALL, ObjectProperties.FILTER_3_ANY_LOAD); if (m.getMessageType() == Message.MESG_TYPE_OBJ_PROP) { return ((ZoneProperties) m); } return null; } /** * Read the properties of a button * * @param number of button * @return ButtonProperties of button, or null if not found * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private ButtonProperties readButtonProperties(int number) throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Message m = c.reqObjectProperties(Message.OBJ_TYPE_BUTTON, number, 0, ObjectProperties.FILTER_1_NAMED, ObjectProperties.FILTER_2_NONE, ObjectProperties.FILTER_3_NONE); if (m.getMessageType() == Message.MESG_TYPE_OBJ_PROP) { return ((ButtonProperties) m); } return null; } /** * Populates all know audio sources which are used by known zones * * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private void readAllAudioSources() throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { int objnum = 0; Message m; while ((m = c.reqObjectProperties(Message.OBJ_TYPE_AUDIO_SOURCE, objnum, 1, ObjectProperties.FILTER_1_NAMED, ObjectProperties.FILTER_2_NONE, ObjectProperties.FILTER_3_NONE)) .getMessageType() == Message.MESG_TYPE_OBJ_PROP) { // logger.info(m.toString()); AudioSourceProperties o = ((AudioSourceProperties) m); objnum = ((ObjectProperties) m).getNumber(); Integer number = new Integer(o.getNumber()); AudioSource as = audioSourceMap.get(number); if (as == null) { as = new AudioSource(o); audioSourceMap.put(number, as); } audioSourceMap.put(new Integer(o.getNumber()), as); } } /** * Update audio zone text fields, this is one of the few * things we need to poll for * * @throws IOException * @throws OmniNotConnectedException * @throws OmniInvalidResponseException * @throws OmniUnknownMessageTypeException */ private void updateAudioSourceTexts() throws IOException, OmniNotConnectedException, OmniInvalidResponseException, OmniUnknownMessageTypeException { Iterator<Integer> it = audioSourceMap.keySet().iterator(); while (it.hasNext()) { Integer source = it.next(); int pos = 0; Message m; boolean updated = false; Vector<String> text = new Vector<String>(); while ((m = c.reqAudioSourceStatus(source.intValue(), pos)) .getMessageType() == Message.MESG_TYPE_AUDIO_SOURCE_STATUS) { AudioSourceStatus a = (AudioSourceStatus) m; text.add(a.getSourceData()); pos = a.getPosition(); } AudioSource as = audioSourceMap.get(source); String text2[] = as.getAudioText(); if (text.size() == text2.length) { for (int i = 0; i < text.size(); i++) { if (!text2[i].equals(text.get(i))) { updated = true; } } } else { updated = true; } if (updated) { as.setAudioText(text.toArray(new String[0])); updateAudioZoneText(as); } } } } /** * Updates a AudioZone's source text fields when a * AudioSource changes * * @param as the audio source that has been updated */ private void updateAudioZoneText(AudioSource as) { for (OmniLinkBindingProvider provider : providers) { for (String itemName : provider.getItemNames()) { OmniLinkBindingConfig config = provider.getOmniLinkBindingConfig(itemName); if (config != null) { switch (config.getObjectType()) { case AUDIOZONE_TEXT: case AUDIOZONE_TEXT_FIELD1: case AUDIOZONE_TEXT_FIELD2: case AUDIOZONE_TEXT_FIELD3: { AudioZone az = (AudioZone) config.getDevice(); az.setAudioSource(audioSourceMap); if (az.getProperties().getSource() == as.getProperties().getNumber()) { az.updateItem(provider.getItem(itemName), config, eventPublisher); } } break; default: break; } } } } } /** * Update a device based on a status message from the system * * @param status */ protected void updateDeviceStatus(Status status) { logger.debug("updateDeviceStatus {} {}", status.getNumber(), status.getClass()); Integer number = new Integer(status.getNumber()); if (status instanceof UnitStatus && unitMap.containsKey(number)) { Unit unit = unitMap.get(number); unit.getProperties().updateUnit((UnitStatus) status); updateItemsForDevice(unit); } else if (status instanceof ThermostatStatus && thermostatMap.containsKey(number)) { logger.debug("Updating thermo {}", number); Thermostat thermo = thermostatMap.get(number); thermo.getProperties().updateThermostat((ThermostatStatus) status); updateItemsForDevice(thermo); } else if (status instanceof AudioZoneStatus && audioZoneMap.containsKey(number)) { logger.debug("Updating audioZone {}", number); AudioZone az = audioZoneMap.get(number); az.getProperties().updateAudioZone((AudioZoneStatus) status); updateItemsForDevice(az); } else if (status instanceof AreaStatus && areaMap.containsKey(number)) { logger.debug("Updating area {}", number); Area area = areaMap.get(number); area.getProperties().updateArea((AreaStatus) status); updateItemsForDevice(area); } else if (status instanceof ZoneStatus && zoneMap.containsKey(number)) { logger.debug("Updating zone {}", number); Zone zone = zoneMap.get(number); zone.getProperties().updateZone((ZoneStatus) status); updateItemsForDevice(zone); } else if (status instanceof AuxSensorStatus && auxMap.containsKey(number)) { logger.debug("Updating aux {}", number); Auxiliary aux = auxMap.get(number); aux.getProperties().updateAuxSensor((AuxSensorStatus) status); updateItemsForDevice(aux); } } /** * Update any items linked to a Omni device. * * @param device */ protected void updateItemsForDevice(OmnilinkDevice device) { for (OmniLinkBindingProvider provider : providers) { for (String itemName : provider.getItemNames()) { OmniLinkBindingConfig bindingConfig = provider.getOmniLinkBindingConfig(itemName); OmnilinkDevice itemDevice = bindingConfig.getDevice(); Item item = provider.getItem(itemName); if (itemDevice != null && itemDevice == device) { device.updateItem(item, bindingConfig, eventPublisher); } } } } @Override public void objectStausNotification(ObjectStatus status) { Status[] statuses = status.getStatuses(); for (Status s : statuses) { updateDeviceStatus(s); } } @Override public void otherEventNotification(OtherEventNotifications other) { } }