From b48609d78a325506ec9df743d7c6b87b89010051 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Mon, 14 Nov 2016 10:39:36 +0100 Subject: [PATCH 1/4] fix wrong DMX retransmitting scheme Signed-off-by: Jan N. Klug --- .../dmx/internal/core/DmxController.java | 31 +++++++++++- .../dmx/internal/core/DmxTransmitter.java | 48 +++++++++++++++++-- .../configurations/openhab_default.cfg | 9 +++- 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java index e9f7f21384f..1952add23b6 100644 --- a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java +++ b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java @@ -27,6 +27,7 @@ * Default DMX Service implementation * * @author Davy Vanherbergen + * @author Jan N. Klug * @since 1.2.0 */ public class DmxController implements DmxService, ManagedService { @@ -34,6 +35,7 @@ public class DmxController implements DmxService, ManagedService { private static Logger logger = LoggerFactory.getLogger(DmxController.class); private static int TRANSMIT_FREQUENCY_MS = 35; + private int repeatMode = DmxTransmitter.REPEAT_MODE_ALWAYS; // default is send every update /** Thread in which the DMX transmitter is running **/ private Timer transmitterTimer; @@ -49,7 +51,6 @@ public class DmxController implements DmxService, ManagedService { */ @Override public void start() throws Exception { - logger.trace("Starting Dmx transmitter ..."); transmitter = new DmxTransmitter(this); transmitterTimer = new Timer(true); @@ -84,7 +85,6 @@ public void setChannelValue(int channel, int value) { */ @Override public int getChannelValue(int channel) { - int value = transmitter.getChannel(channel).getValue(); logger.trace("Getting channel {} value: {}", channel, value); return value; @@ -292,11 +292,38 @@ public void unsetConnection(DmxConnection conn) { @Override public void updated(Dictionary config) throws ConfigurationException { if (config != null) { + // connection String configuredConnection = (String) config.get("connection"); if (StringUtils.isNotBlank(configuredConnection)) { connectionString = configuredConnection; logger.debug("Setting connection from config: {}", connectionString); } + // refresh timeout (i.e. interval between transmits if nothing changed) + String configuredRepeatMode = ((String) config.get("repeatMode")).toLowerCase(); + if (StringUtils.isNotBlank(configuredRepeatMode)) { + if (configuredRepeatMode.matches("always")) { + repeatMode = DmxTransmitter.REPEAT_MODE_ALWAYS; + logger.debug("repeatMode set to always"); + } else if (configuredRepeatMode.matches("never")) { + repeatMode = DmxTransmitter.REPEAT_MODE_NEVER; + logger.debug("repeatMode set to never"); + } else if (configuredRepeatMode.matches("reduced")) { + repeatMode = DmxTransmitter.REPEAT_MODE_REDUCED; + logger.debug("repeatMode set to reduced"); + } else { + repeatMode = DmxTransmitter.REPEAT_MODE_ALWAYS; + logger.warn("repeatMode not recognized, set to default 'always'"); + } + if (transmitter != null) { + transmitter.setRepeatMode(repeatMode); + } + } + } + // close connection so that the new connection string will take effekt on next getConnection + if (connection != null) { + if (!connection.isClosed()) { + connection.close(); + } } } diff --git a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java index 95da85adf44..aaed4bc27d4 100644 --- a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java +++ b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java @@ -27,6 +27,14 @@ */ public final class DmxTransmitter extends TimerTask { + /* REPEAT_INTERVAL is 750 ms (results in 800-1000ms) repetition time */ + private static final int REPEAT_INTERVAL = 750; + private static final int REPEAT_COUNT = 3; + + public static final int REPEAT_MODE_ALWAYS = 0; + public static final int REPEAT_MODE_NEVER = 1; + public static final int REPEAT_MODE_REDUCED = 2; + private static Logger logger = LoggerFactory.getLogger(DmxTransmitter.class); private DmxUniverse universe = new DmxUniverse(); @@ -34,9 +42,13 @@ public final class DmxTransmitter extends TimerTask { private DmxService service; private boolean running; + private int repeatMode = 0; private boolean suspended; + private long lastTransmit = 0; + private int packetRepeatCount = 0; + /** * Default constructor. */ @@ -56,13 +68,31 @@ public void run() { running = true; try { + long now = System.currentTimeMillis(); byte[] b = universe.calculateBuffer(); - if (universe.getBufferChanged()) { + if (universe.getBufferChanged() || (repeatMode == REPEAT_MODE_ALWAYS)) { + logger.trace("DMX Buffer changed or repeat mode always"); DmxConnection conn = service.getConnection(); if (conn != null) { conn.sendDmx(b); universe.notifyStatusListeners(); } + lastTransmit = now; + packetRepeatCount = 0; + } else if ((repeatMode == REPEAT_MODE_REDUCED) + && ((packetRepeatCount < REPEAT_COUNT) || ((now - lastTransmit) > REPEAT_INTERVAL))) { + logger.trace("DMX Buffer needs refresh, sending"); + DmxConnection conn = service.getConnection(); + if (conn != null) { + conn.sendDmx(b); + universe.notifyStatusListeners(); + } + if (packetRepeatCount < REPEAT_COUNT) { + packetRepeatCount++; + } + lastTransmit = now; + } else { + logger.trace("DMX output suppressed"); } } catch (Exception e) { logger.error("Error sending dmx values.", e); @@ -79,8 +109,8 @@ public boolean isRunning() { } /** - * Suspend/resume transmittting. - * + * Suspend/resume transmitting. + * * @param suspend * true to suspend */ @@ -88,9 +118,19 @@ public void setSuspend(boolean suspend) { this.suspended = suspend; } + /** + * change transmitter refresh cycle + * + * @param refreshInterval + * interval in ms (if output did not change) + */ + public void setRepeatMode(int repeatMode) { + this.repeatMode = repeatMode; + } + /** * Get the DMX channel in the current universe. - * + * * @param channel * number * @return DMX channel diff --git a/distribution/openhabhome/configurations/openhab_default.cfg b/distribution/openhabhome/configurations/openhab_default.cfg index 02e342ec488..2435eaafb0b 100644 --- a/distribution/openhabhome/configurations/openhab_default.cfg +++ b/distribution/openhabhome/configurations/openhab_default.cfg @@ -1,4 +1,4 @@ -# This is the default configuration file, which comes with every openHAB distribution. +# This is the default configuration file, which comes with every openHAB distribution. # You should do a copy of it with the name 'openhab.cfg' and configure your personal # settings in there. This way you can be sure that they are not overwritten, if you # update openHAB one day. @@ -1053,6 +1053,13 @@ ntp:hostname=ptbtime1.ptb.de # 'localhost:9010' or 'localhost:9020' depending on the choosen connection type) #dmx:connection= +# Standard DMX-512A (E1.11) uses continous transmission (option "always", default value). +# Some DMX protocols (sACN/E1.31, ArtNET) allow suppressing packet transmission for +# a short period of time (800-1000ms) to reduce network load (option "reduced"). +# Previous versions of the DMX binding did not repeat unchanged packets at all. While +# this is not in compliance with any standard the option "never" is included for +# backward compatibilty. +#dmx:repeatMode=always ############################### Philips Hue Binding ################################### # # IP address of Hue Bridge (optional, default is auto-discovery) From 980fd86f7491a3e9aa0794e03b80fa9a0679b106 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sun, 20 Nov 2016 10:58:08 +0100 Subject: [PATCH 2/4] reduce status update traffic to "update on change" instead on "update on repeat" Signed-off-by: Jan N. Klug --- .../dmx/internal/core/DmxTransmitter.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java index aaed4bc27d4..7b4118c8157 100644 --- a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java +++ b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java @@ -70,29 +70,29 @@ public void run() { try { long now = System.currentTimeMillis(); byte[] b = universe.calculateBuffer(); - if (universe.getBufferChanged() || (repeatMode == REPEAT_MODE_ALWAYS)) { - logger.trace("DMX Buffer changed or repeat mode always"); - DmxConnection conn = service.getConnection(); - if (conn != null) { + DmxConnection conn = service.getConnection(); + if (conn != null) { + if (universe.getBufferChanged()) { + logger.trace("DMX Buffer changed, also sending status updates"); conn.sendDmx(b); universe.notifyStatusListeners(); - } - lastTransmit = now; - packetRepeatCount = 0; - } else if ((repeatMode == REPEAT_MODE_REDUCED) - && ((packetRepeatCount < REPEAT_COUNT) || ((now - lastTransmit) > REPEAT_INTERVAL))) { - logger.trace("DMX Buffer needs refresh, sending"); - DmxConnection conn = service.getConnection(); - if (conn != null) { + lastTransmit = now; + packetRepeatCount = 0; + } else if (repeatMode == REPEAT_MODE_ALWAYS) { + logger.trace("repeat mode always, sending DMX only"); conn.sendDmx(b); - universe.notifyStatusListeners(); - } - if (packetRepeatCount < REPEAT_COUNT) { - packetRepeatCount++; + lastTransmit = now; + } else if ((repeatMode == REPEAT_MODE_REDUCED) + && ((packetRepeatCount < REPEAT_COUNT) || ((now - lastTransmit) > REPEAT_INTERVAL))) { + logger.trace("output needs refresh, sending DMX only"); + conn.sendDmx(b); + if (packetRepeatCount < REPEAT_COUNT) { + packetRepeatCount++; + } + lastTransmit = now; + } else { + logger.trace("DMX output suppressed"); } - lastTransmit = now; - } else { - logger.trace("DMX output suppressed"); } } catch (Exception e) { logger.error("Error sending dmx values.", e); From 399ed6dc36387ef6390931fa190b07ee12ba7a92 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Fri, 25 Nov 2016 10:43:57 +0100 Subject: [PATCH 3/4] change to enmum - untested - do not merge --- .../dmx/internal/core/DmxController.java | 21 ++++------ .../dmx/internal/core/DmxTransmitter.java | 39 +++++++++++++++---- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java index 1952add23b6..fdff0582773 100644 --- a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java +++ b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java @@ -35,7 +35,7 @@ public class DmxController implements DmxService, ManagedService { private static Logger logger = LoggerFactory.getLogger(DmxController.class); private static int TRANSMIT_FREQUENCY_MS = 35; - private int repeatMode = DmxTransmitter.REPEAT_MODE_ALWAYS; // default is send every update + private DmxRepeatMode repeatMode = DmxTransmitter.DmxRepeatMode.ALWAYS; // default is send every update /** Thread in which the DMX transmitter is running **/ private Timer transmitterTimer; @@ -299,21 +299,16 @@ public void updated(Dictionary config) throws ConfigurationException logger.debug("Setting connection from config: {}", connectionString); } // refresh timeout (i.e. interval between transmits if nothing changed) - String configuredRepeatMode = ((String) config.get("repeatMode")).toLowerCase(); + String configuredRepeatMode = ((String) config.get("repeatMode")); if (StringUtils.isNotBlank(configuredRepeatMode)) { - if (configuredRepeatMode.matches("always")) { - repeatMode = DmxTransmitter.REPEAT_MODE_ALWAYS; - logger.debug("repeatMode set to always"); - } else if (configuredRepeatMode.matches("never")) { - repeatMode = DmxTransmitter.REPEAT_MODE_NEVER; - logger.debug("repeatMode set to never"); - } else if (configuredRepeatMode.matches("reduced")) { - repeatMode = DmxTransmitter.REPEAT_MODE_REDUCED; - logger.debug("repeatMode set to reduced"); + repeatMode = DmxTransmitter.DmxRepeatMode(configuredRepeatMode); + if (repeatMode==null) { + repeatMode = DmxTransmitter.DmxRepeatMode.ALWAYS; + logger.error("repeatMode {} not recognized, set to {}", configuredRepeatMode, repeatMode); } else { - repeatMode = DmxTransmitter.REPEAT_MODE_ALWAYS; - logger.warn("repeatMode not recognized, set to default 'always'"); + logger.debug("repeatMode set to {}", repeatMode.toString()); } + if (transmitter != null) { transmitter.setRepeatMode(repeatMode); } diff --git a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java index 7b4118c8157..3abab21f976 100644 --- a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java +++ b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java @@ -31,10 +31,33 @@ public final class DmxTransmitter extends TimerTask { private static final int REPEAT_INTERVAL = 750; private static final int REPEAT_COUNT = 3; - public static final int REPEAT_MODE_ALWAYS = 0; - public static final int REPEAT_MODE_NEVER = 1; - public static final int REPEAT_MODE_REDUCED = 2; - + public enum DmxRepeatMode { + ALWAYS('always'), + NEVER('never'), + REDUCED('reduced') + + private String repeatMode; + + DmxRepeatMode(String repeatMode) { + this.repeatMode = repeatMode; + } + + public String toString() { + return this.repeatMode; + } + + public static DmxRepeatMode fromString(String repeatMode) { + if (repeatMode != null) { + for (DmxRepeatMode mode : DmxRepeatMode.values()) { + if (repeatMode.equalsIgnoreCase(mode.repeatMode)) { + return mode; + } + } + } + return null; + } + } + private static Logger logger = LoggerFactory.getLogger(DmxTransmitter.class); private DmxUniverse universe = new DmxUniverse(); @@ -42,7 +65,7 @@ public final class DmxTransmitter extends TimerTask { private DmxService service; private boolean running; - private int repeatMode = 0; + private DmxRepeatMode repeatMode = DmxRepeatMode.ALWAYS; private boolean suspended; @@ -78,11 +101,11 @@ public void run() { universe.notifyStatusListeners(); lastTransmit = now; packetRepeatCount = 0; - } else if (repeatMode == REPEAT_MODE_ALWAYS) { + } else if (repeatMode == DmxRepeatMode.ALWAYS) { logger.trace("repeat mode always, sending DMX only"); conn.sendDmx(b); lastTransmit = now; - } else if ((repeatMode == REPEAT_MODE_REDUCED) + } else if ((repeatMode == DmxRepeatMode.REDUCED) && ((packetRepeatCount < REPEAT_COUNT) || ((now - lastTransmit) > REPEAT_INTERVAL))) { logger.trace("output needs refresh, sending DMX only"); conn.sendDmx(b); @@ -124,7 +147,7 @@ public void setSuspend(boolean suspend) { * @param refreshInterval * interval in ms (if output did not change) */ - public void setRepeatMode(int repeatMode) { + public void setRepeatMode(DmxRepeatMode repeatMode) { this.repeatMode = repeatMode; } From 6d92177a772bb3d47d02f96e6797af0dae2c74fa Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Fri, 25 Nov 2016 16:02:29 +0100 Subject: [PATCH 4/4] fixes Signed-off-by: Jan N. Klug --- .../dmx/internal/core/DmxController.java | 9 ++++--- .../dmx/internal/core/DmxTransmitter.java | 27 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java index fdff0582773..c4e83e7d7c7 100644 --- a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java +++ b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxController.java @@ -35,7 +35,8 @@ public class DmxController implements DmxService, ManagedService { private static Logger logger = LoggerFactory.getLogger(DmxController.class); private static int TRANSMIT_FREQUENCY_MS = 35; - private DmxRepeatMode repeatMode = DmxTransmitter.DmxRepeatMode.ALWAYS; // default is send every update + private DmxTransmitter.DmxRepeatMode repeatMode = DmxTransmitter.DmxRepeatMode.ALWAYS; // default is send every + // update /** Thread in which the DMX transmitter is running **/ private Timer transmitterTimer; @@ -301,14 +302,14 @@ public void updated(Dictionary config) throws ConfigurationException // refresh timeout (i.e. interval between transmits if nothing changed) String configuredRepeatMode = ((String) config.get("repeatMode")); if (StringUtils.isNotBlank(configuredRepeatMode)) { - repeatMode = DmxTransmitter.DmxRepeatMode(configuredRepeatMode); - if (repeatMode==null) { + repeatMode = DmxTransmitter.DmxRepeatMode.fromString(configuredRepeatMode); + if (repeatMode == null) { repeatMode = DmxTransmitter.DmxRepeatMode.ALWAYS; logger.error("repeatMode {} not recognized, set to {}", configuredRepeatMode, repeatMode); } else { logger.debug("repeatMode set to {}", repeatMode.toString()); } - + if (transmitter != null) { transmitter.setRepeatMode(repeatMode); } diff --git a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java index 3abab21f976..c79f59a4e3d 100644 --- a/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java +++ b/bundles/binding/org.openhab.binding.dmx/src/main/java/org/openhab/binding/dmx/internal/core/DmxTransmitter.java @@ -32,32 +32,33 @@ public final class DmxTransmitter extends TimerTask { private static final int REPEAT_COUNT = 3; public enum DmxRepeatMode { - ALWAYS('always'), - NEVER('never'), - REDUCED('reduced') - + ALWAYS("always"), + NEVER("never"), + REDUCED("reduced"); + private String repeatMode; DmxRepeatMode(String repeatMode) { - this.repeatMode = repeatMode; + this.repeatMode = repeatMode; } - + + @Override public String toString() { return this.repeatMode; } - + public static DmxRepeatMode fromString(String repeatMode) { if (repeatMode != null) { - for (DmxRepeatMode mode : DmxRepeatMode.values()) { - if (repeatMode.equalsIgnoreCase(mode.repeatMode)) { - return mode; + for (DmxRepeatMode mode : DmxRepeatMode.values()) { + if (repeatMode.equalsIgnoreCase(mode.repeatMode)) { + return mode; + } } - } } return null; - } + } } - + private static Logger logger = LoggerFactory.getLogger(DmxTransmitter.class); private DmxUniverse universe = new DmxUniverse();