diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/AwtrixLightBindingConstants.java b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/AwtrixLightBindingConstants.java index 4e75fb8cec..002a80e2e4 100644 --- a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/AwtrixLightBindingConstants.java +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/AwtrixLightBindingConstants.java @@ -57,6 +57,7 @@ public class AwtrixLightBindingConstants { public static final String TOPIC_INDICATOR1 = "/indicator1"; public static final String TOPIC_INDICATOR2 = "/indicator2"; public static final String TOPIC_INDICATOR3 = "/indicator3"; + public static final String TOPIC_LWT = "/stats/device"; public static final String TOPIC_NOTIFY = "/notify"; public static final String TOPIC_POWER = "/power"; public static final String TOPIC_REBOOT = "/reboot"; diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/Helper.java b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/Helper.java index 31ded6a09f..93b3fb4117 100644 --- a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/Helper.java +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/Helper.java @@ -67,9 +67,11 @@ public class Helper { String[] pixelStrings = cutBrackets.split(","); int[] values = Arrays.stream(pixelStrings).mapToInt(Integer::parseInt).toArray(); + + int numPixels = SCREEN_HEIGHT * SCREEN_WIDTH; int[][] pixels = new int[SCREEN_HEIGHT][SCREEN_WIDTH]; - for (int i = 0; i < 256; i++) { - pixels[i / 32][i % 32] = values[i]; + for (int i = 0; i < numPixels; i++) { + pixels[i / SCREEN_WIDTH][i % SCREEN_WIDTH] = values[i]; } // Resize and add gaps between pixels @@ -97,7 +99,7 @@ public class Helper { } } - byte[] bytes = new byte[256]; + byte[] bytes = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image, "png", baos); diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightAppHandler.java b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightAppHandler.java index fa0f8bc9fd..3c2aab6f72 100644 --- a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightAppHandler.java +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightAppHandler.java @@ -631,7 +631,14 @@ public class AwtrixLightAppHandler extends BaseThingHandler implements MqttMessa updateApp(); } } - updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE); + ThingStatus bridgeStatus = getBridgeStatus().getStatus(); + if (ThingStatus.ONLINE == bridgeStatus) { + updateStatus(ThingStatus.ONLINE); + } else if (ThingStatus.OFFLINE == bridgeStatus) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); + } else { + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.BRIDGE_UNINITIALIZED); + } Future localJob = this.finishInitJob; if (localJob != null) { localJob.cancel(true); diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightBridgeHandler.java b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightBridgeHandler.java index 8cb5fb62bc..8dbd27e70e 100644 --- a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightBridgeHandler.java +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/java/org/openhab/binding/mqtt/awtrixlight/internal/handler/AwtrixLightBridgeHandler.java @@ -81,6 +81,7 @@ public class AwtrixLightBridgeHandler extends BaseBridgeHandler implements MqttM private String channelPrefix = ""; private String currentApp = ""; private boolean discoverDefaultApps = false; + private boolean deviceOnline = false; private int lowBatteryThreshold = 25; private Map appHandlers = new HashMap(); @@ -187,10 +188,16 @@ public class AwtrixLightBridgeHandler extends BaseBridgeHandler implements MqttM public void processMessage(String topic, byte[] payload) { String payloadString = new String(payload, StandardCharsets.UTF_8); if (topic.endsWith(TOPIC_STATS)) { - if (thing.getStatus() != ThingStatus.ONLINE) { + ThingStatusInfo statusInfo = getThing().getStatusInfo(); + if (ThingStatus.UNKNOWN == statusInfo.getStatus() + && ThingStatusDetail.CONFIGURATION_PENDING == statusInfo.getStatusDetail()) { + // Obviously the device is online. We just haven't received a LWT message yet. + this.deviceOnline = true; updateStatus(ThingStatus.ONLINE); } handleStatsMessage(payloadString); + } else if (topic.endsWith(TOPIC_LWT)) { + handleLwtMessage(payloadString); } else if (topic.endsWith(TOPIC_STATS_CURRENT_APP)) { handleCurrentAppMessage(payloadString); } else if (topic.endsWith(TOPIC_SCREEN)) { @@ -236,6 +243,7 @@ public class AwtrixLightBridgeHandler extends BaseBridgeHandler implements MqttM } ThingHandler handler = localBridge.getHandler(); if (handler instanceof AbstractBrokerHandler abh) { + @Nullable final MqttBrokerConnection connection; try { connection = abh.getConnectionAsync().get(500, TimeUnit.MILLISECONDS); @@ -245,11 +253,18 @@ public class AwtrixLightBridgeHandler extends BaseBridgeHandler implements MqttM return; } this.connection = connection; - updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING, - "Waiting for first MQTT message to be received."); + if (this.deviceOnline) { + updateStatus(ThingStatus.ONLINE); + } else { + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING, "Waiting for LWT message."); + } + connection.subscribe(this.basetopic + TOPIC_LWT, this); connection.subscribe(this.basetopic + TOPIC_STATS + "/#", this); connection.subscribe(this.basetopic + TOPIC_STATS_CURRENT_APP + "/#", this); connection.subscribe(this.basetopic + TOPIC_SCREEN + "/#", this); + for (Map.Entry entry : this.appHandlers.entrySet()) { + connection.subscribe(this.basetopic + "/custom/" + entry.getKey(), entry.getValue()); + } } return; } @@ -263,6 +278,7 @@ public class AwtrixLightBridgeHandler extends BaseBridgeHandler implements MqttM leaveAppControlMode(); MqttBrokerConnection localConnection = connection; if (localConnection != null) { + localConnection.unsubscribe(this.basetopic + TOPIC_LWT, this); localConnection.unsubscribe(this.basetopic + TOPIC_STATS + "/#", this); localConnection.unsubscribe(this.basetopic + TOPIC_STATS_CURRENT_APP + "/#", this); localConnection.unsubscribe(this.basetopic + TOPIC_SCREEN + "/#", this); @@ -634,4 +650,9 @@ public class AwtrixLightBridgeHandler extends BaseBridgeHandler implements MqttM } } } + + private void handleLwtMessage(String lwtMessage) { + this.deviceOnline = "online".equals(lwtMessage); + updateStatus(this.deviceOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE); + } } diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/i18n/mqtt.properties b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/i18n/mqtt.properties new file mode 100644 index 0000000000..269a953749 --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/i18n/mqtt.properties @@ -0,0 +1,162 @@ +# thing types + +thing-type.mqtt.awtrix-app.label = Awtrix App +thing-type.mqtt.awtrix-app.description = An app for an Awtrix Light device +thing-type.mqtt.awtrix-app.channel.active.label = App Active +thing-type.mqtt.awtrix-app.channel.active.description = App is removed from rotation while inactive +thing-type.mqtt.awtrix-app.channel.button-left.label = Button Left +thing-type.mqtt.awtrix-app.channel.button-left.description = Left button pressed +thing-type.mqtt.awtrix-app.channel.button-right.label = Button Right +thing-type.mqtt.awtrix-app.channel.button-right.description = Right button pressed +thing-type.mqtt.awtrix-app.channel.button-select.label = Button Select +thing-type.mqtt.awtrix-app.channel.button-select.description = Select button pressed +thing-type.mqtt.awtrix-clock.label = Awtrix Light Device +thing-type.mqtt.awtrix-clock.description = Device with Awtrix Light firmware +thing-type.mqtt.awtrix-clock.channel.button-left.label = Button Left +thing-type.mqtt.awtrix-clock.channel.button-left.description = Left button pressed +thing-type.mqtt.awtrix-clock.channel.button-right.label = Button Right +thing-type.mqtt.awtrix-clock.channel.button-right.description = Right button pressed +thing-type.mqtt.awtrix-clock.channel.button-select.label = Button Select +thing-type.mqtt.awtrix-clock.channel.button-select.description = Select button pressed +thing-type.mqtt.awtrix-clock.channel.display.label = Display Power +thing-type.mqtt.awtrix-clock.channel.display.description = Switches the display ON or OFF +thing-type.mqtt.awtrix-clock.channel.indicator-1.label = Indicator 1 +thing-type.mqtt.awtrix-clock.channel.indicator-2.label = Indicator 2 +thing-type.mqtt.awtrix-clock.channel.indicator-3.label = Indicator 3 + +# thing types config + +thing-type.config.mqtt.awtrix-app.appname.label = App Name +thing-type.config.mqtt.awtrix-app.appname.description = Name of the app +thing-type.config.mqtt.awtrix-app.useButtons.label = Button Controlled +thing-type.config.mqtt.awtrix-app.useButtons.description = Activate if the app can be controlled by the user. The select button locks on current app and the app will emit subsequent button events until the appLockTimeout of the bridge is reached. Every button press before the timeout will reset timeout. +thing-type.config.mqtt.awtrix-clock.appLockTimeout.label = App Selection Timeout +thing-type.config.mqtt.awtrix-clock.appLockTimeout.description = Timeout in seconds until selected apps return control and the app rotation continues. +thing-type.config.mqtt.awtrix-clock.basetopic.label = Base Topic +thing-type.config.mqtt.awtrix-clock.basetopic.description = Base topic as configured in the Awtrix Light device. +thing-type.config.mqtt.awtrix-clock.discoverDefaultApps.label = Discover Built-in Apps +thing-type.config.mqtt.awtrix-clock.discoverDefaultApps.description = Currently changing settings for the built-in default apps is not implemented. It is therefore recommended to ignore them during app discovery. +thing-type.config.mqtt.awtrix-clock.lowBatteryThreshold.label = Low Battery Threshold +thing-type.config.mqtt.awtrix-clock.lowBatteryThreshold.description = Threshold for issuing a low battery warning. + +# channel types + +channel-type.mqtt.app.label = Active App +channel-type.mqtt.app.description = App currently shown on screen +channel-type.mqtt.auto-brightness.label = Automatic Brightness +channel-type.mqtt.auto-brightness.description = Let the clock set brightness automatically based on internal brightness sensor readings +channel-type.mqtt.autoscale.label = Autoscale Graphs +channel-type.mqtt.autoscale.description = Automatically scales graphs to fit onto display +channel-type.mqtt.background.label = Background Color +channel-type.mqtt.background.description = Color for display background +channel-type.mqtt.bar.label = Bar Graph +channel-type.mqtt.bar.description = Draw a bar graph (format: "value1,value2,value3", last 16 entries will be displayed, last 11 with icon) +channel-type.mqtt.blink-text.label = Blink Text +channel-type.mqtt.blink-text.description = Blink text in specified time interval +channel-type.mqtt.brightness.label = Display Brightness +channel-type.mqtt.brightness.description = Screen brightness in percent +channel-type.mqtt.center.label = Center Text +channel-type.mqtt.center.description = Short texts will be centered instead of scrolling +channel-type.mqtt.duration.label = Duration +channel-type.mqtt.duration.description = How long the app should be displayed +channel-type.mqtt.effect-blend.label = Smooth Effects +channel-type.mqtt.effect-blend.description = Smoother effect animations +channel-type.mqtt.effect-palette.label = Effect Color Palette +channel-type.mqtt.effect-palette.description = Changes the color scheme of the effect settings +channel-type.mqtt.effect-palette.state.option.None = None +channel-type.mqtt.effect-palette.state.option.Cloud = Cloud +channel-type.mqtt.effect-palette.state.option.Lava = Lava +channel-type.mqtt.effect-palette.state.option.Ocean = Ocean +channel-type.mqtt.effect-palette.state.option.Forest = Forest +channel-type.mqtt.effect-palette.state.option.Stripe = Stripe +channel-type.mqtt.effect-palette.state.option.Party = Party +channel-type.mqtt.effect-palette.state.option.Heat = Heat +channel-type.mqtt.effect-palette.state.option.Rainbow = Rainbow +channel-type.mqtt.effect-speed.label = Background Effect Speed +channel-type.mqtt.effect-speed.description = Playback speed of background animations +channel-type.mqtt.effect.label = Background Effect +channel-type.mqtt.effect.description = Effect shown in the background of the app +channel-type.mqtt.effect.state.option.None = None +channel-type.mqtt.effect.state.option.BrickBreaker = BrickBreaker +channel-type.mqtt.effect.state.option.Fireworks = Fireworks +channel-type.mqtt.effect.state.option.Radar = Radar +channel-type.mqtt.effect.state.option.Snake = Snake +channel-type.mqtt.effect.state.option.TheaterChase = Theater Chase +channel-type.mqtt.effect.state.option.SwirlOut = Swirl Out +channel-type.mqtt.effect.state.option.LookingEyes = Looking Eyes +channel-type.mqtt.effect.state.option.Pacifica = Pacifica +channel-type.mqtt.effect.state.option.PlasmaCloud = Plasma Cloud +channel-type.mqtt.effect.state.option.Checkerboard = Checkerboard +channel-type.mqtt.effect.state.option.PingPong = Ping Pong +channel-type.mqtt.effect.state.option.Ripple = Ripple +channel-type.mqtt.effect.state.option.TwinklingStars = Twinkling Stars +channel-type.mqtt.effect.state.option.ColorWaves = Color Waves +channel-type.mqtt.effect.state.option.SwirlIn = Swirl In +channel-type.mqtt.effect.state.option.Matrix = Matrix +channel-type.mqtt.effect.state.option.Plasma = Plasma +channel-type.mqtt.effect.state.option.MovingLine = Moving Line +channel-type.mqtt.fade-text.label = Fade Text +channel-type.mqtt.fade-text.description = Fade text in specified interval +channel-type.mqtt.gradient-color.label = Gradient Color +channel-type.mqtt.gradient-color.description = Color text as gradient from Main Color to Gradient Color +channel-type.mqtt.icon.label = Icon +channel-type.mqtt.icon.description = Icon ID or filename without extension +channel-type.mqtt.indicator.label = Indicator +channel-type.mqtt.indicator.description = Indicator state +channel-type.mqtt.lifetime-mode.label = App Lifetime Mode +channel-type.mqtt.lifetime-mode.description = Delete the app or mark as stale after lifetime +channel-type.mqtt.lifetime-mode.state.option.DELETE = Delete +channel-type.mqtt.lifetime-mode.state.option.STALE = Mark stale +channel-type.mqtt.lifetime.label = App Lifetime +channel-type.mqtt.lifetime.description = Remove the app if there was no update within specified seconds +channel-type.mqtt.line.label = Line Graph +channel-type.mqtt.line.description = Draw a line graph (format: "value1,value2,value3", last 16 entries will be displayed, last 11 with icon) +channel-type.mqtt.lux.label = Lux +channel-type.mqtt.lux.description = Brightness in lux +channel-type.mqtt.main-color.label = Main Color +channel-type.mqtt.main-color.description = Color to display text and charts on the screen +channel-type.mqtt.overlay.label = App Overlay +channel-type.mqtt.overlay.description = Overlay effect (overriden by global clock overlay) +channel-type.mqtt.overlay.state.option.clear = Clear +channel-type.mqtt.overlay.state.option.snow = Snow +channel-type.mqtt.overlay.state.option.rain = Rain +channel-type.mqtt.overlay.state.option.drizzle = Drizzle +channel-type.mqtt.overlay.state.option.storm = Storm +channel-type.mqtt.overlay.state.option.thunder = Thunder +channel-type.mqtt.overlay.state.option.frost = Frost +channel-type.mqtt.progress-background.label = Progress Bar Background +channel-type.mqtt.progress-background.description = Color of progress bar background +channel-type.mqtt.progress-color.label = Progress Bar Color +channel-type.mqtt.progress-color.description = Color of progress bar +channel-type.mqtt.progress.label = Progress Bar +channel-type.mqtt.progress.description = Show progress bar with specified percentage +channel-type.mqtt.push-icon.label = Scroll Icon +channel-type.mqtt.push-icon.description = Make the icon scroll along with the text +channel-type.mqtt.push-icon.state.option.STATIC = Icon does not move +channel-type.mqtt.push-icon.state.option.PUSHOUT = Icon moves and disappears +channel-type.mqtt.push-icon.state.option.PUSHOUTRETURN = Icon moves and reappears +channel-type.mqtt.rainbow.label = Rainbow Color +channel-type.mqtt.rainbow.description = Fades the text color in rainbow colors +channel-type.mqtt.reset.label = Reset +channel-type.mqtt.reset.description = Resets the app and the linked items to the default settings +channel-type.mqtt.rssi.label = WiFi Signal +channel-type.mqtt.rssi.description = RSSI value of WiFi signal +channel-type.mqtt.rtttl.label = Play RTTTL +channel-type.mqtt.rtttl.description = Ring Tone Text Transfer Language (RTTTL) compliant sound string +channel-type.mqtt.screen.label = Screen Mirror +channel-type.mqtt.screen.description = Mirror screen image from the clock. By default only refreshed on app change. Refresh can be also triggered with a RefreshType command. +channel-type.mqtt.scroll-speed.label = Scroll Speed +channel-type.mqtt.scroll-speed.description = Speed of text scrolling as percentage of default speed +channel-type.mqtt.sound.label = Play Melody +channel-type.mqtt.sound.description = Name of the melody file in the MELODIES folder +channel-type.mqtt.text-case.label = Text Case +channel-type.mqtt.text-case.description = Change case of displayed text. Default uses the global preset. +channel-type.mqtt.text-case.state.option.0 = Default +channel-type.mqtt.text-case.state.option.1 = Uppercase +channel-type.mqtt.text-case.state.option.2 = Unchanged +channel-type.mqtt.text-offset.label = Text Offset +channel-type.mqtt.text-offset.description = Offset on x-axis in pixel for displayed text +channel-type.mqtt.text.label = Display Text +channel-type.mqtt.text.description = Text displayed in the app +channel-type.mqtt.top-text.label = Top Text +channel-type.mqtt.top-text.description = Aligns the text with the top of the display diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/thing/thing-types.xml index 29c673755f..2626848524 100644 --- a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/thing/thing-types.xml @@ -34,9 +34,15 @@ recommend - - - + + + + + + + + + @@ -49,6 +55,7 @@ + 1 uniqueId @@ -63,6 +70,8 @@ screen + + App is removed from rotation while inactive recommend @@ -111,6 +120,7 @@ + 1 appid diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/update/awtrix-app-updates.xml b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/update/awtrix-app-updates.xml new file mode 100644 index 0000000000..68d02369f6 --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/update/awtrix-app-updates.xml @@ -0,0 +1,16 @@ + + + + + + + system:power + + App is removed from rotation while inactive + + + + + diff --git a/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/update/awtrix-clock-updates.xml b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/update/awtrix-clock-updates.xml new file mode 100644 index 0000000000..6aea5933a6 --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.awtrixlight/src/main/resources/OH-INF/update/awtrix-clock-updates.xml @@ -0,0 +1,23 @@ + + + + + + + mqtt:indicator + + + + mqtt:indicator + + + + mqtt:indicator + + + + + +