diff --git a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java index e1d5da2ef59..2ba8ad2aa1b 100644 --- a/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java +++ b/bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/ChannelState.java @@ -78,13 +78,35 @@ public class ChannelState implements MqttMessageSubscriber { */ public ChannelState(ChannelConfig config, ChannelUID channelUID, Value cachedValue, @Nullable ChannelStateUpdateListener channelStateUpdateListener) { + this(config, channelUID, cachedValue, channelStateUpdateListener, + new ChannelTransformation(config.transformationPattern), + new ChannelTransformation(config.transformationPatternOut)); + } + + /** + * Creates a new channel state. + * + * @param config The channel configuration + * @param channelUID The channelUID is used for the {@link ChannelStateUpdateListener} to notify about value changes + * @param cachedValue MQTT only notifies us once about a value, during the subscribe. The channel state therefore + * needs a cache for the current value. + * @param channelStateUpdateListener A channel state update listener + * @param incomingTransformation A transformation to apply to incoming values + * @param outgoingTransformation A transformation to apply to outgoing values + */ + public ChannelState(ChannelConfig config, ChannelUID channelUID, Value cachedValue, + @Nullable ChannelStateUpdateListener channelStateUpdateListener, + @Nullable ChannelTransformation incomingTransformation, + @Nullable ChannelTransformation outgoingTransformation) { this.config = config; this.channelStateUpdateListener = channelStateUpdateListener; this.channelUID = channelUID; this.cachedValue = cachedValue; this.readOnly = config.commandTopic.isBlank(); - this.incomingTransformation = new ChannelTransformation(config.transformationPattern); - this.outgoingTransformation = new ChannelTransformation(config.transformationPatternOut); + this.incomingTransformation = incomingTransformation == null ? new ChannelTransformation((String) null) + : incomingTransformation; + this.outgoingTransformation = outgoingTransformation == null ? new ChannelTransformation((String) null) + : outgoingTransformation; } public boolean isReadOnly() { diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/README.md b/bundles/org.openhab.binding.mqtt.homeassistant/README.md index 93205168af9..f65261c18bf 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/README.md +++ b/bundles/org.openhab.binding.mqtt.homeassistant/README.md @@ -6,15 +6,6 @@ Devices that use [Home Assistant MQTT Discovery](https://www.home-assistant.io/i Components that share a common `device.identifiers` will automatically be grouped together as a single Thing. Each component will be represented as a Channel Group, with the attributes of that component being individual channels. -## Requirements - -The Home Assistant MQTT binding requires two transformations to be installed: - -- JINJA-Transformations -- JSONPath-Transformations - -These can be installed under `Settings` → `Addon` → `Transformations` - ## Discovery Any device that publishes the component configuration under the `homeassistant` prefix in MQTT will have their components automatically discovered and added to the Inbox. diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/noEmbedDependencies.profile b/bundles/org.openhab.binding.mqtt.homeassistant/noEmbedDependencies.profile new file mode 100644 index 00000000000..e69de29bb2d diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml b/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml index 79773a7dc24..854983ad21f 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml +++ b/bundles/org.openhab.binding.mqtt.homeassistant/pom.xml @@ -35,21 +35,22 @@ - org.openhab.addons.bundles - org.openhab.transform.jinja - ${project.version} - test + org.openhab.osgiify + com.hubspot.jinjava.jinjava + 2.7.2_0 + compile - com.hubspot.jinjava - jinjava - 2.7.2 - test - - - com.google.re2j - re2j + org.openhab.osgiify + com.google.re2j.re2j 1.2 + compile + + + ch.obermuhlner + big-math + 2.3.2 + compile diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/feature/feature.xml b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/feature/feature.xml index fd50c3169fc..853e170e1cf 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/feature/feature.xml +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/feature/feature.xml @@ -5,6 +5,10 @@ openhab-runtime-base openhab-transport-mqtt + openhab.tp-commons-net + mvn:org.openhab.osgiify/com.hubspot.jinjava.jinjava/2.7.2_0 + mvn:org.openhab.osgiify/com.google.re2j.re2j/1.2 + mvn:ch.obermuhlner/big-math/2.3.2 mvn:org.openhab.addons.bundles/org.openhab.binding.mqtt/${project.version} mvn:org.openhab.addons.bundles/org.openhab.binding.mqtt.generic/${project.version} mvn:org.openhab.addons.bundles/org.openhab.binding.mqtt.homeassistant/${project.version} diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/generic/internal/MqttThingHandlerFactory.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/generic/internal/MqttThingHandlerFactory.java index b228b1b0e3b..6c5ebdd8886 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/generic/internal/MqttThingHandlerFactory.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/generic/internal/MqttThingHandlerFactory.java @@ -31,6 +31,8 @@ import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import com.hubspot.jinjava.Jinjava; + /** * The {@link MqttThingHandlerFactory} is responsible for creating things and thing * handlers. @@ -43,6 +45,7 @@ public class MqttThingHandlerFactory extends BaseThingHandlerFactory { private final MqttChannelTypeProvider typeProvider; private final MqttChannelStateDescriptionProvider stateDescriptionProvider; private final ChannelTypeRegistry channelTypeRegistry; + private final Jinjava jinjava = new Jinjava(); private static final Set SUPPORTED_THING_TYPES_UIDS = Stream .of(MqttBindingConstants.HOMEASSISTANT_MQTT_THING).collect(Collectors.toSet()); @@ -72,7 +75,7 @@ public class MqttThingHandlerFactory extends BaseThingHandlerFactory { if (supportsThingType(thingTypeUID)) { return new HomeAssistantThingHandler(thing, typeProvider, stateDescriptionProvider, channelTypeRegistry, - 10000, 2000); + jinjava, 10000, 2000); } return null; } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java index c8bb949f42b..df7b926870b 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/ComponentChannel.java @@ -12,7 +12,6 @@ */ package org.openhab.binding.mqtt.homeassistant.internal; -import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ScheduledExecutorService; @@ -30,6 +29,7 @@ import org.openhab.core.io.transport.mqtt.MqttBrokerConnection; import org.openhab.core.thing.Channel; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.binding.builder.ChannelBuilder; +import org.openhab.core.thing.binding.generic.ChannelTransformation; import org.openhab.core.thing.type.AutoUpdatePolicy; import org.openhab.core.thing.type.ChannelDefinition; import org.openhab.core.thing.type.ChannelDefinitionBuilder; @@ -223,21 +223,26 @@ public class ComponentChannel { ChannelUID channelUID; ChannelState channelState; Channel channel; + ChannelTransformation incomingTransformation = null, outgoingTransformation = null; channelUID = component.buildChannelUID(channelID); ChannelConfigBuilder channelConfigBuilder = ChannelConfigBuilder.create().withRetain(retain).withQos(qos) .withStateTopic(stateTopic).withCommandTopic(commandTopic).makeTrigger(trigger) .withFormatter(format); - if (templateIn != null) { - channelConfigBuilder.withTransformationPattern(List.of(JINJA + ":" + templateIn)); + String localTemplateIn = templateIn; + if (localTemplateIn != null) { + incomingTransformation = new HomeAssistantChannelTransformation(component.getJinjava(), component, + localTemplateIn); } - if (templateOut != null) { - channelConfigBuilder.withTransformationPatternOut(List.of(JINJA + ":" + templateOut)); + String localTemplateOut = templateOut; + if (localTemplateOut != null) { + outgoingTransformation = new HomeAssistantChannelTransformation(component.getJinjava(), component, + localTemplateOut); } channelState = new HomeAssistantChannelState(channelConfigBuilder.build(), channelUID, valueState, - channelStateUpdateListener, commandFilter); + channelStateUpdateListener, commandFilter, incomingTransformation, outgoingTransformation); // disabled by default components should always show up as advanced if (!component.isEnabledByDefault()) { diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/DiscoverComponents.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/DiscoverComponents.java index 7f23a13aed2..810d99d988d 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/DiscoverComponents.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/DiscoverComponents.java @@ -37,6 +37,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.Gson; +import com.hubspot.jinjava.Jinjava; /** * Responsible for subscribing to the HomeAssistant MQTT components wildcard topic, either @@ -55,6 +56,7 @@ public class DiscoverComponents implements MqttMessageSubscriber { protected final CompletableFuture<@Nullable Void> discoverFinishedFuture = new CompletableFuture<>(); private final Gson gson; + private final Jinjava jinjava; private @Nullable ScheduledFuture stopDiscoveryFuture; private WeakReference<@Nullable MqttBrokerConnection> connectionRef = new WeakReference<>(null); @@ -78,11 +80,12 @@ public class DiscoverComponents implements MqttMessageSubscriber { */ public DiscoverComponents(ThingUID thingUID, ScheduledExecutorService scheduler, ChannelStateUpdateListener channelStateUpdateListener, AvailabilityTracker tracker, Gson gson, - boolean newStyleChannels) { + Jinjava jinjava, boolean newStyleChannels) { this.thingUID = thingUID; this.scheduler = scheduler; this.updateListener = channelStateUpdateListener; this.gson = gson; + this.jinjava = jinjava; this.tracker = tracker; this.newStyleChannels = newStyleChannels; } @@ -100,7 +103,7 @@ public class DiscoverComponents implements MqttMessageSubscriber { if (config.length() > 0) { try { component = ComponentFactory.createComponent(thingUID, haID, config, updateListener, tracker, scheduler, - gson, newStyleChannels); + gson, jinjava, newStyleChannels); component.setConfigSeen(); logger.trace("Found HomeAssistant component {}", haID); diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/HomeAssistantChannelState.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/HomeAssistantChannelState.java index 16fb5303dac..84afd134883 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/HomeAssistantChannelState.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/HomeAssistantChannelState.java @@ -22,6 +22,7 @@ import org.openhab.binding.mqtt.generic.ChannelState; import org.openhab.binding.mqtt.generic.ChannelStateUpdateListener; import org.openhab.binding.mqtt.generic.values.Value; import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.binding.generic.ChannelTransformation; import org.openhab.core.types.Command; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,9 +49,11 @@ public class HomeAssistantChannelState extends ChannelState { * false ignored. Can be null to publish all commands. */ public HomeAssistantChannelState(ChannelConfig config, ChannelUID channelUID, Value cachedValue, - @Nullable ChannelStateUpdateListener channelStateUpdateListener, - @Nullable Predicate commandFilter) { - super(config, channelUID, cachedValue, channelStateUpdateListener); + @Nullable ChannelStateUpdateListener channelStateUpdateListener, @Nullable Predicate commandFilter, + @Nullable ChannelTransformation incomingTransformation, + @Nullable ChannelTransformation outgoingTransformation) { + super(config, channelUID, cachedValue, channelStateUpdateListener, incomingTransformation, + outgoingTransformation); this.commandFilter = commandFilter; } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/HomeAssistantChannelTransformation.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/HomeAssistantChannelTransformation.java new file mode 100644 index 00000000000..3a51c77bf2d --- /dev/null +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/HomeAssistantChannelTransformation.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2010-2024 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.mqtt.homeassistant.internal; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.mqtt.homeassistant.internal.component.AbstractComponent; +import org.openhab.core.thing.binding.generic.ChannelTransformation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.hubspot.jinjava.Jinjava; +import com.hubspot.jinjava.interpret.FatalTemplateErrorsException; + +/** + * Provides a channel transformation for a Home Assistant channel with a + * Jinja2 template, providing the additional context and extensions required by Home Assistant + * Based in part on the JinjaTransformationService + * + * @author Cody Cutrer - Initial contribution + */ +@NonNullByDefault +public class HomeAssistantChannelTransformation extends ChannelTransformation { + private final Logger logger = LoggerFactory.getLogger(HomeAssistantChannelTransformation.class); + + private final Jinjava jinjava; + private final AbstractComponent component; + private final String template; + private final ObjectMapper objectMapper = new ObjectMapper(); + + public HomeAssistantChannelTransformation(Jinjava jinjava, AbstractComponent component, String template) { + super((String) null); + this.jinjava = jinjava; + this.component = component; + this.template = template; + } + + @Override + public boolean isEmpty() { + return template.isEmpty(); + } + + @Override + public Optional apply(String value) { + String transformationResult; + Map bindings = new HashMap<>(); + + logger.debug("about to transform '{}' by the function '{}'", value, template); + + bindings.put("value", value); + + try { + JsonNode tree = objectMapper.readTree(value); + bindings.put("value_json", toObject(tree)); + } catch (IOException e) { + // ok, then value_json is null... + } + + try { + transformationResult = jinjava.render(template, bindings); + } catch (FatalTemplateErrorsException e) { + logger.warn("Applying template {} for component {} failed: {}", template, + component.getHaID().toShortTopic(), e.getMessage()); + return Optional.empty(); + } + + logger.debug("transformation resulted in '{}'", transformationResult); + + return Optional.of(transformationResult); + } + + private static @Nullable Object toObject(JsonNode node) { + switch (node.getNodeType()) { + case ARRAY: { + List<@Nullable Object> result = new ArrayList<>(); + for (JsonNode el : node) { + result.add(toObject(el)); + } + return result; + } + case NUMBER: + return node.decimalValue(); + case OBJECT: { + Map result = new HashMap<>(); + Iterator> it = node.fields(); + while (it.hasNext()) { + Entry field = it.next(); + result.put(field.getKey(), toObject(field.getValue())); + } + return result; + } + case STRING: + return node.asText(); + case BOOLEAN: + return node.asBoolean(); + case NULL: + default: + return null; + } + } +} diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponent.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponent.java index ccff4d3db0c..131cc81d65c 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponent.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponent.java @@ -49,6 +49,7 @@ import org.openhab.core.types.CommandDescription; import org.openhab.core.types.StateDescription; import com.google.gson.Gson; +import com.hubspot.jinjava.Jinjava; /** * A HomeAssistant component is comparable to a channel group. @@ -334,6 +335,10 @@ public abstract class AbstractComponent return componentConfiguration.getGson(); } + public Jinjava getJinjava() { + return componentConfiguration.getJinjava(); + } + public C getChannelConfiguration() { return channelConfiguration; } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java index 1acc4ac18bd..36e9bbd66bd 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/ComponentFactory.java @@ -24,6 +24,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.exception.UnsupportedComp import org.openhab.core.thing.ThingUID; import com.google.gson.Gson; +import com.hubspot.jinjava.Jinjava; /** * A factory to create HomeAssistant MQTT components. Those components are specified at: @@ -46,9 +47,9 @@ public class ComponentFactory { */ public static AbstractComponent createComponent(ThingUID thingUID, HaID haID, String channelConfigurationJSON, ChannelStateUpdateListener updateListener, AvailabilityTracker tracker, ScheduledExecutorService scheduler, - Gson gson, boolean newStyleChannels) throws ConfigurationException { + Gson gson, Jinjava jinjava, boolean newStyleChannels) throws ConfigurationException { ComponentConfiguration componentConfiguration = new ComponentConfiguration(thingUID, haID, - channelConfigurationJSON, gson, updateListener, tracker, scheduler); + channelConfigurationJSON, gson, jinjava, updateListener, tracker, scheduler); switch (haID.component) { case "alarm_control_panel": return new AlarmControlPanel(componentConfiguration, newStyleChannels); @@ -96,6 +97,7 @@ public class ComponentFactory { private final ChannelStateUpdateListener updateListener; private final AvailabilityTracker tracker; private final Gson gson; + private final Jinjava jinjava; private final ScheduledExecutorService scheduler; /** @@ -106,13 +108,14 @@ public class ComponentFactory { * @param configJSON The configuration string * @param gson A Gson instance */ - protected ComponentConfiguration(ThingUID thingUID, HaID haID, String configJSON, Gson gson, + protected ComponentConfiguration(ThingUID thingUID, HaID haID, String configJSON, Gson gson, Jinjava jinjava, ChannelStateUpdateListener updateListener, AvailabilityTracker tracker, ScheduledExecutorService scheduler) { this.thingUID = thingUID; this.haID = haID; this.configJSON = configJSON; this.gson = gson; + this.jinjava = jinjava; this.updateListener = updateListener; this.tracker = tracker; this.scheduler = scheduler; @@ -138,6 +141,10 @@ public class ComponentFactory { return gson; } + public Jinjava getJinjava() { + return jinjava; + } + public AvailabilityTracker getTracker() { return tracker; } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandler.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandler.java index fb9e68e862f..8c19ce7efe3 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandler.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/main/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandler.java @@ -59,6 +59,7 @@ import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.hubspot.jinjava.Jinjava; /** * Handles HomeAssistant MQTT object things. Such an HA Object can have multiple HA Components with different instances @@ -90,6 +91,7 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler protected final MqttChannelTypeProvider channelTypeProvider; protected final MqttChannelStateDescriptionProvider stateDescriptionProvider; protected final ChannelTypeRegistry channelTypeRegistry; + protected final Jinjava jinjava; public final int attributeReceiveTimeout; protected final DelayedBatchProcessing> delayedProcessing; protected final DiscoverComponents discoverComponents; @@ -115,18 +117,20 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler */ public HomeAssistantThingHandler(Thing thing, MqttChannelTypeProvider channelTypeProvider, MqttChannelStateDescriptionProvider stateDescriptionProvider, ChannelTypeRegistry channelTypeRegistry, - int subscribeTimeout, int attributeReceiveTimeout) { + Jinjava jinjava, int subscribeTimeout, int attributeReceiveTimeout) { super(thing, subscribeTimeout); this.gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create(); this.channelTypeProvider = channelTypeProvider; this.stateDescriptionProvider = stateDescriptionProvider; this.channelTypeRegistry = channelTypeRegistry; + this.jinjava = jinjava; this.attributeReceiveTimeout = attributeReceiveTimeout; this.delayedProcessing = new DelayedBatchProcessing<>(attributeReceiveTimeout, this, scheduler); newStyleChannels = "true".equals(thing.getProperties().get("newStyleChannels")); - this.discoverComponents = new DiscoverComponents(thing.getUID(), scheduler, this, this, gson, newStyleChannels); + this.discoverComponents = new DiscoverComponents(thing.getUID(), scheduler, this, this, gson, jinjava, + newStyleChannels); } @Override @@ -156,7 +160,7 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler } else { try { component = ComponentFactory.createComponent(thingUID, haID, channelConfigurationJSON, this, this, - scheduler, gson, newStyleChannels); + scheduler, gson, jinjava, newStyleChannels); if (typeID.equals(MqttBindingConstants.HOMEASSISTANT_MQTT_THING)) { typeID = calculateThingTypeUID(component); } diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/AbstractHomeAssistantTests.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/AbstractHomeAssistantTests.java index 3e3de4afbff..4ef9d6e2668 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/AbstractHomeAssistantTests.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/AbstractHomeAssistantTests.java @@ -32,7 +32,6 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; @@ -59,8 +58,6 @@ import org.openhab.core.thing.type.ThingTypeBuilder; import org.openhab.core.thing.type.ThingTypeRegistry; import org.openhab.core.transform.TransformationHelper; import org.openhab.core.transform.TransformationService; -import org.openhab.transform.jinja.internal.JinjaTransformationService; -import org.openhab.transform.jinja.internal.profiles.JinjaTransformationProfile; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; @@ -107,14 +104,8 @@ public abstract class AbstractHomeAssistantTests extends JavaTest { private @NonNullByDefault({}) TransformationHelper transformationHelper; - private final JinjaTransformationService jinjaTransformationService = new JinjaTransformationService(); - @BeforeEach public void beforeEachAbstractHomeAssistantTests() { - Mockito.when(serviceRefMock.getProperty(any())).thenReturn(JinjaTransformationProfile.PROFILE_TYPE_UID.getId()); - - Mockito.when(bundleContextMock.getService(serviceRefMock)).thenReturn(jinjaTransformationService); - transformationHelper = new TransformationHelper(bundleContextMock); transformationHelper.setTransformationService(serviceRefMock); diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponentTests.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponentTests.java index bc63d783ea1..dc7d2b1ef1d 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponentTests.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponentTests.java @@ -49,6 +49,8 @@ import org.openhab.core.thing.type.ChannelTypeRegistry; import org.openhab.core.types.Command; import org.openhab.core.types.State; +import com.hubspot.jinjava.Jinjava; + /** * Abstract class for components tests. * @@ -288,8 +290,8 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests public LatchThingHandler(Thing thing, MqttChannelTypeProvider channelTypeProvider, MqttChannelStateDescriptionProvider stateDescriptionProvider, ChannelTypeRegistry channelTypeRegistry, int subscribeTimeout, int attributeReceiveTimeout) { - super(thing, channelTypeProvider, stateDescriptionProvider, channelTypeRegistry, subscribeTimeout, - attributeReceiveTimeout); + super(thing, channelTypeProvider, stateDescriptionProvider, channelTypeRegistry, new Jinjava(), + subscribeTimeout, attributeReceiveTimeout); } @Override diff --git a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandlerTests.java b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandlerTests.java index acf5990420c..ab469881547 100644 --- a/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandlerTests.java +++ b/bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/handler/HomeAssistantThingHandlerTests.java @@ -39,6 +39,8 @@ import org.openhab.core.thing.Channel; import org.openhab.core.thing.binding.ThingHandlerCallback; import org.openhab.core.types.StateDescription; +import com.hubspot.jinjava.Jinjava; + /** * Tests for {@link HomeAssistantThingHandler} * @@ -75,7 +77,7 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests { when(callbackMock.getBridge(eq(BRIDGE_UID))).thenReturn(bridgeThing); thingHandler = new HomeAssistantThingHandler(haThing, channelTypeProvider, stateDescriptionProvider, - channelTypeRegistry, SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT); + channelTypeRegistry, new Jinjava(), SUBSCRIBE_TIMEOUT, ATTRIBUTE_RECEIVE_TIMEOUT); thingHandler.setConnection(bridgeConnection); thingHandler.setCallback(callbackMock); nonSpyThingHandler = thingHandler; diff --git a/features/openhab-addons/src/main/resources/footer.xml b/features/openhab-addons/src/main/resources/footer.xml index df421579366..383959548d4 100644 --- a/features/openhab-addons/src/main/resources/footer.xml +++ b/features/openhab-addons/src/main/resources/footer.xml @@ -22,6 +22,10 @@ openhab-runtime-base openhab-transport-mqtt + openhab.tp-commons-net + mvn:org.openhab.osgiify/com.hubspot.jinjava.jinjava/2.7.2_0 + mvn:org.openhab.osgiify/com.google.re2j.re2j/1.2 + mvn:ch.obermuhlner/big-math/2.3.2 mvn:org.openhab.addons.bundles/org.openhab.binding.mqtt/${project.version} mvn:org.openhab.addons.bundles/org.openhab.binding.mqtt.espmilighthub/${project.version} mvn:org.openhab.addons.bundles/org.openhab.binding.mqtt.generic/${project.version} diff --git a/itests/org.openhab.binding.mqtt.homeassistant.tests/itest.bndrun b/itests/org.openhab.binding.mqtt.homeassistant.tests/itest.bndrun index 226f765ca26..b6d41e1a2e8 100644 --- a/itests/org.openhab.binding.mqtt.homeassistant.tests/itest.bndrun +++ b/itests/org.openhab.binding.mqtt.homeassistant.tests/itest.bndrun @@ -116,4 +116,18 @@ Import-Package: \ org.openhab.core.io.transport.mqtt;version='[4.3.0,4.3.1)',\ org.openhab.core.test;version='[4.3.0,4.3.1)',\ org.openhab.core.thing;version='[4.3.0,4.3.1)',\ - org.openhab.core.transform;version='[4.3.0,4.3.1)' + org.openhab.core.transform;version='[4.3.0,4.3.1)',\ + ch.obermuhlner.math.big;version='[2.3.2,2.3.3)',\ + com.fasterxml.jackson.core.jackson-annotations;version='[2.17.1,2.17.2)',\ + com.fasterxml.jackson.core.jackson-core;version='[2.17.1,2.17.2)',\ + com.fasterxml.jackson.core.jackson-databind;version='[2.17.1,2.17.2)',\ + com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.17.1,2.17.2)',\ + com.google.guava;version='[33.2.0,33.2.1)',\ + com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ + com.google.re2j.re2j;version='[1.2.0,1.2.1)',\ + com.hubspot.jinjava.jinjava;version='[2.7.2,2.7.3)',\ + javassist;version='[3.29.2,3.29.3)',\ + org.apache.commons.commons-net;version='[3.9.0,3.9.1)',\ + org.apache.commons.lang3;version='[3.14.0,3.14.1)',\ + org.osgi.service.cm;version='[1.6.0,1.6.1)',\ + org.yaml.snakeyaml;version='[2.2.0,2.2.1)' diff --git a/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/DiscoverComponentsTest.java b/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/DiscoverComponentsTest.java index 5ab82f8347b..903c94a00d7 100644 --- a/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/DiscoverComponentsTest.java +++ b/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/DiscoverComponentsTest.java @@ -46,6 +46,7 @@ import org.openhab.core.test.java.JavaOSGiTest; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.hubspot.jinjava.Jinjava; /** * Tests the {@link DiscoverComponents} class. @@ -79,9 +80,10 @@ public class DiscoverComponentsTest extends JavaOSGiTest { ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1); Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create(); + Jinjava jinjava = new Jinjava(); DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING, - scheduler, channelStateUpdateListener, availabilityTracker, gson, true)); + scheduler, channelStateUpdateListener, availabilityTracker, gson, jinjava, true)); HandlerConfiguration config = new HandlerConfiguration("homeassistant", List.of("switch/object")); diff --git a/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/HomeAssistantMQTTImplementationTest.java b/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/HomeAssistantMQTTImplementationTest.java index 04a732c9296..2f273661d3b 100644 --- a/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/HomeAssistantMQTTImplementationTest.java +++ b/itests/org.openhab.binding.mqtt.homeassistant.tests/src/main/java/org/openhab/binding/mqtt/homeassistant/HomeAssistantMQTTImplementationTest.java @@ -57,6 +57,7 @@ import org.openhab.core.types.UnDefType; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.hubspot.jinjava.Jinjava; /** * A full implementation test, that starts the embedded MQTT broker and publishes a homeassistant MQTT discovery device @@ -143,10 +144,11 @@ public class HomeAssistantMQTTImplementationTest extends MqttOSGiTest { final Map> haComponents = new HashMap<>(); Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ChannelConfigurationTypeAdapterFactory()).create(); + Jinjava jinjava = new Jinjava(); ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(4); DiscoverComponents discover = spy(new DiscoverComponents(ThingChannelConstants.TEST_HOME_ASSISTANT_THING, - scheduler, channelStateUpdateListener, availabilityTracker, gson, true)); + scheduler, channelStateUpdateListener, availabilityTracker, gson, jinjava, true)); // The DiscoverComponents object calls ComponentDiscovered callbacks. // In the following implementation we add the found component to the `haComponents` map