[mqtt.homeassistant] handle null component name (#15427)
* [mqtt.homeassistant] handle null component name channels from such components will not have a group. this is now done by zigbee2mqtt for the "default" component of a device, such as the light. HASS encourages this as of release 2023.8 Signed-off-by: Cody Cutrer <cody@cutrer.us>
This commit is contained in:
parent
a535caa13c
commit
7fc351c9c2
@ -224,7 +224,7 @@ public class ComponentChannel {
|
|||||||
ChannelType type;
|
ChannelType type;
|
||||||
ChannelTypeUID channelTypeUID;
|
ChannelTypeUID channelTypeUID;
|
||||||
|
|
||||||
channelUID = new ChannelUID(component.getGroupUID(), channelID);
|
channelUID = component.buildChannelUID(channelID);
|
||||||
channelTypeUID = new ChannelTypeUID(MqttBindingConstants.BINDING_ID,
|
channelTypeUID = new ChannelTypeUID(MqttBindingConstants.BINDING_ID,
|
||||||
channelUID.getGroupId() + "_" + channelID);
|
channelUID.getGroupId() + "_" + channelID);
|
||||||
channelState = new HomeAssistantChannelState(
|
channelState = new HomeAssistantChannelState(
|
||||||
|
|||||||
@ -14,6 +14,7 @@ package org.openhab.binding.mqtt.homeassistant.internal.component;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@ -31,8 +32,10 @@ import org.openhab.binding.mqtt.homeassistant.internal.ComponentChannel;
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
import org.openhab.binding.mqtt.homeassistant.internal.HaID;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.component.ComponentFactory.ComponentConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.component.ComponentFactory.ComponentConfiguration;
|
||||||
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
|
||||||
|
import org.openhab.binding.mqtt.homeassistant.internal.config.dto.Device;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.thing.ChannelGroupUID;
|
import org.openhab.core.thing.ChannelGroupUID;
|
||||||
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.type.ChannelDefinition;
|
import org.openhab.core.thing.type.ChannelDefinition;
|
||||||
import org.openhab.core.thing.type.ChannelGroupDefinition;
|
import org.openhab.core.thing.type.ChannelGroupDefinition;
|
||||||
import org.openhab.core.thing.type.ChannelGroupType;
|
import org.openhab.core.thing.type.ChannelGroupType;
|
||||||
@ -54,8 +57,8 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
|||||||
|
|
||||||
// Component location fields
|
// Component location fields
|
||||||
private final ComponentConfiguration componentConfiguration;
|
private final ComponentConfiguration componentConfiguration;
|
||||||
protected final ChannelGroupTypeUID channelGroupTypeUID;
|
protected final @Nullable ChannelGroupTypeUID channelGroupTypeUID;
|
||||||
protected final ChannelGroupUID channelGroupUID;
|
protected final @Nullable ChannelGroupUID channelGroupUID;
|
||||||
protected final HaID haID;
|
protected final HaID haID;
|
||||||
|
|
||||||
// Channels and configuration
|
// Channels and configuration
|
||||||
@ -83,10 +86,15 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
|||||||
|
|
||||||
this.haID = componentConfiguration.getHaID();
|
this.haID = componentConfiguration.getHaID();
|
||||||
|
|
||||||
|
if (channelConfiguration.getName() != null) {
|
||||||
String groupId = this.haID.getGroupId(channelConfiguration.getUniqueId());
|
String groupId = this.haID.getGroupId(channelConfiguration.getUniqueId());
|
||||||
|
|
||||||
this.channelGroupTypeUID = new ChannelGroupTypeUID(MqttBindingConstants.BINDING_ID, groupId);
|
this.channelGroupTypeUID = new ChannelGroupTypeUID(MqttBindingConstants.BINDING_ID, groupId);
|
||||||
this.channelGroupUID = new ChannelGroupUID(componentConfiguration.getThingUID(), groupId);
|
this.channelGroupUID = new ChannelGroupUID(componentConfiguration.getThingUID(), groupId);
|
||||||
|
} else {
|
||||||
|
this.channelGroupTypeUID = null;
|
||||||
|
this.channelGroupUID = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.configSeen = false;
|
this.configSeen = false;
|
||||||
|
|
||||||
@ -142,7 +150,10 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
|||||||
* @param channelTypeProvider The channel type provider
|
* @param channelTypeProvider The channel type provider
|
||||||
*/
|
*/
|
||||||
public void addChannelTypes(MqttChannelTypeProvider channelTypeProvider) {
|
public void addChannelTypes(MqttChannelTypeProvider channelTypeProvider) {
|
||||||
channelTypeProvider.setChannelGroupType(getGroupTypeUID(), getType());
|
ChannelGroupTypeUID groupTypeUID = channelGroupTypeUID;
|
||||||
|
if (groupTypeUID != null) {
|
||||||
|
channelTypeProvider.setChannelGroupType(groupTypeUID, Objects.requireNonNull(getType()));
|
||||||
|
}
|
||||||
channels.values().forEach(v -> v.addChannelTypes(channelTypeProvider));
|
channels.values().forEach(v -> v.addChannelTypes(channelTypeProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,20 +165,31 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
|||||||
*/
|
*/
|
||||||
public void removeChannelTypes(MqttChannelTypeProvider channelTypeProvider) {
|
public void removeChannelTypes(MqttChannelTypeProvider channelTypeProvider) {
|
||||||
channels.values().forEach(v -> v.removeChannelTypes(channelTypeProvider));
|
channels.values().forEach(v -> v.removeChannelTypes(channelTypeProvider));
|
||||||
channelTypeProvider.removeChannelGroupType(getGroupTypeUID());
|
ChannelGroupTypeUID groupTypeUID = channelGroupTypeUID;
|
||||||
|
if (groupTypeUID != null) {
|
||||||
|
channelTypeProvider.removeChannelGroupType(groupTypeUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelUID buildChannelUID(String channelID) {
|
||||||
|
final ChannelGroupUID groupUID = channelGroupUID;
|
||||||
|
if (groupUID != null) {
|
||||||
|
return new ChannelUID(groupUID, channelID);
|
||||||
|
}
|
||||||
|
return new ChannelUID(componentConfiguration.getThingUID(), channelID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each HomeAssistant component corresponds to a Channel Group Type.
|
* Each HomeAssistant component corresponds to a Channel Group Type.
|
||||||
*/
|
*/
|
||||||
public ChannelGroupTypeUID getGroupTypeUID() {
|
public @Nullable ChannelGroupTypeUID getGroupTypeUID() {
|
||||||
return channelGroupTypeUID;
|
return channelGroupTypeUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unique id of this component.
|
* The unique id of this component.
|
||||||
*/
|
*/
|
||||||
public ChannelGroupUID getGroupUID() {
|
public @Nullable ChannelGroupUID getGroupUID() {
|
||||||
return channelGroupUID;
|
return channelGroupUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +197,16 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
|||||||
* Component (Channel Group) name.
|
* Component (Channel Group) name.
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return channelConfiguration.getName();
|
String result = channelConfiguration.getName();
|
||||||
|
|
||||||
|
Device device = channelConfiguration.getDevice();
|
||||||
|
if (result == null && device != null) {
|
||||||
|
result = device.getName();
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
result = haID.objectID;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,11 +238,19 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
|||||||
/**
|
/**
|
||||||
* Return the channel group type.
|
* Return the channel group type.
|
||||||
*/
|
*/
|
||||||
public ChannelGroupType getType() {
|
public @Nullable ChannelGroupType getType() {
|
||||||
|
ChannelGroupTypeUID groupTypeUID = channelGroupTypeUID;
|
||||||
|
if (groupTypeUID == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final List<ChannelDefinition> channelDefinitions = channels.values().stream().map(ComponentChannel::type)
|
final List<ChannelDefinition> channelDefinitions = channels.values().stream().map(ComponentChannel::type)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
return ChannelGroupTypeBuilder.instance(channelGroupTypeUID, getName())
|
return ChannelGroupTypeBuilder.instance(groupTypeUID, getName()).withChannelDefinitions(channelDefinitions)
|
||||||
.withChannelDefinitions(channelDefinitions).build();
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ChannelDefinition> getChannels() {
|
||||||
|
return channels.values().stream().map(ComponentChannel::type).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -225,8 +264,12 @@ public abstract class AbstractComponent<C extends AbstractChannelConfiguration>
|
|||||||
/**
|
/**
|
||||||
* Return the channel group definition for this component.
|
* Return the channel group definition for this component.
|
||||||
*/
|
*/
|
||||||
public ChannelGroupDefinition getGroupDefinition() {
|
public @Nullable ChannelGroupDefinition getGroupDefinition() {
|
||||||
return new ChannelGroupDefinition(channelGroupUID.getId(), getGroupTypeUID(), getName(), null);
|
ChannelGroupTypeUID groupTypeUID = channelGroupTypeUID;
|
||||||
|
if (groupTypeUID == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ChannelGroupDefinition(channelGroupUID.getId(), groupTypeUID, getName(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HaID getHaID() {
|
public HaID getHaID() {
|
||||||
|
|||||||
@ -74,24 +74,23 @@ public class AlarmControlPanel extends AbstractComponent<AlarmControlPanel.Chann
|
|||||||
final String[] stateEnum = { channelConfiguration.stateDisarmed, channelConfiguration.stateArmedHome,
|
final String[] stateEnum = { channelConfiguration.stateDisarmed, channelConfiguration.stateArmedHome,
|
||||||
channelConfiguration.stateArmedAway, channelConfiguration.statePending,
|
channelConfiguration.stateArmedAway, channelConfiguration.statePending,
|
||||||
channelConfiguration.stateTriggered };
|
channelConfiguration.stateTriggered };
|
||||||
buildChannel(STATE_CHANNEL_ID, new TextValue(stateEnum), channelConfiguration.getName(),
|
buildChannel(STATE_CHANNEL_ID, new TextValue(stateEnum), getName(), componentConfiguration.getUpdateListener())
|
||||||
componentConfiguration.getUpdateListener())
|
|
||||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())//
|
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())//
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
String commandTopic = channelConfiguration.commandTopic;
|
String commandTopic = channelConfiguration.commandTopic;
|
||||||
if (commandTopic != null) {
|
if (commandTopic != null) {
|
||||||
buildChannel(SWITCH_DISARM_CHANNEL_ID, new TextValue(new String[] { channelConfiguration.payloadDisarm }),
|
buildChannel(SWITCH_DISARM_CHANNEL_ID, new TextValue(new String[] { channelConfiguration.payloadDisarm }),
|
||||||
channelConfiguration.getName(), componentConfiguration.getUpdateListener())
|
getName(), componentConfiguration.getUpdateListener())
|
||||||
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos()).build();
|
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos()).build();
|
||||||
|
|
||||||
buildChannel(SWITCH_ARM_HOME_CHANNEL_ID,
|
buildChannel(SWITCH_ARM_HOME_CHANNEL_ID,
|
||||||
new TextValue(new String[] { channelConfiguration.payloadArmHome }), channelConfiguration.getName(),
|
new TextValue(new String[] { channelConfiguration.payloadArmHome }), getName(),
|
||||||
componentConfiguration.getUpdateListener())
|
componentConfiguration.getUpdateListener())
|
||||||
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos()).build();
|
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos()).build();
|
||||||
|
|
||||||
buildChannel(SWITCH_ARM_AWAY_CHANNEL_ID,
|
buildChannel(SWITCH_ARM_AWAY_CHANNEL_ID,
|
||||||
new TextValue(new String[] { channelConfiguration.payloadArmAway }), channelConfiguration.getName(),
|
new TextValue(new String[] { channelConfiguration.payloadArmAway }), getName(),
|
||||||
componentConfiguration.getUpdateListener())
|
componentConfiguration.getUpdateListener())
|
||||||
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos()).build();
|
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos()).build();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ public class Camera extends AbstractComponent<Camera.ChannelConfiguration> {
|
|||||||
|
|
||||||
ImageValue value = new ImageValue();
|
ImageValue value = new ImageValue();
|
||||||
|
|
||||||
buildChannel(CAMERA_CHANNEL_ID, value, channelConfiguration.getName(),
|
buildChannel(CAMERA_CHANNEL_ID, value, getName(), componentConfiguration.getUpdateListener())
|
||||||
componentConfiguration.getUpdateListener()).stateTopic(channelConfiguration.topic).build();
|
.stateTopic(channelConfiguration.topic).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -286,7 +286,7 @@ public class Climate extends AbstractComponent<Climate.ChannelConfiguration> {
|
|||||||
@Nullable String commandTopic, @Nullable String stateTemplate, @Nullable String stateTopic,
|
@Nullable String commandTopic, @Nullable String stateTemplate, @Nullable String stateTopic,
|
||||||
@Nullable Predicate<Command> commandFilter) {
|
@Nullable Predicate<Command> commandFilter) {
|
||||||
if ((commandTopic != null && !commandTopic.isBlank()) || (stateTopic != null && !stateTopic.isBlank())) {
|
if ((commandTopic != null && !commandTopic.isBlank()) || (stateTopic != null && !stateTopic.isBlank())) {
|
||||||
return buildChannel(channelId, valueState, channelConfiguration.getName(), channelStateUpdateListener)
|
return buildChannel(channelId, valueState, getName(), channelStateUpdateListener)
|
||||||
.stateTopic(stateTopic, stateTemplate, channelConfiguration.getValueTemplate())
|
.stateTopic(stateTopic, stateTemplate, channelConfiguration.getValueTemplate())
|
||||||
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos(),
|
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos(),
|
||||||
commandTemplate)
|
commandTemplate)
|
||||||
|
|||||||
@ -56,8 +56,7 @@ public class Cover extends AbstractComponent<Cover.ChannelConfiguration> {
|
|||||||
RollershutterValue value = new RollershutterValue(channelConfiguration.payloadOpen,
|
RollershutterValue value = new RollershutterValue(channelConfiguration.payloadOpen,
|
||||||
channelConfiguration.payloadClose, channelConfiguration.payloadStop);
|
channelConfiguration.payloadClose, channelConfiguration.payloadStop);
|
||||||
|
|
||||||
buildChannel(SWITCH_CHANNEL_ID, value, channelConfiguration.getName(),
|
buildChannel(SWITCH_CHANNEL_ID, value, getName(), componentConfiguration.getUpdateListener())
|
||||||
componentConfiguration.getUpdateListener())
|
|
||||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
||||||
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
||||||
channelConfiguration.getQos())
|
channelConfiguration.getQos())
|
||||||
|
|||||||
@ -281,7 +281,7 @@ public class DefaultSchemaLight extends Light {
|
|||||||
colorValue.update(newOnState);
|
colorValue.update(newOnState);
|
||||||
}
|
}
|
||||||
|
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID),
|
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID),
|
||||||
state.equals(OnOffType.ON) ? newOnState : HSBType.BLACK);
|
state.equals(OnOffType.ON) ? newOnState : HSBType.BLACK);
|
||||||
} else if (brightnessChannel != null) {
|
} else if (brightnessChannel != null) {
|
||||||
listener.updateChannelState(new ChannelUID(channel.getThingUID(), BRIGHTNESS_CHANNEL_ID),
|
listener.updateChannelState(new ChannelUID(channel.getThingUID(), BRIGHTNESS_CHANNEL_ID),
|
||||||
@ -301,8 +301,7 @@ public class DefaultSchemaLight extends Light {
|
|||||||
colorValue.update(new HSBType(DecimalType.ZERO, PercentType.ZERO,
|
colorValue.update(new HSBType(DecimalType.ZERO, PercentType.ZERO,
|
||||||
(PercentType) brightnessValue.getChannelState()));
|
(PercentType) brightnessValue.getChannelState()));
|
||||||
}
|
}
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID),
|
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
|
||||||
colorValue.getChannelState());
|
|
||||||
} else {
|
} else {
|
||||||
listener.updateChannelState(channel, state);
|
listener.updateChannelState(channel, state);
|
||||||
}
|
}
|
||||||
@ -330,13 +329,11 @@ public class DefaultSchemaLight extends Light {
|
|||||||
HSBType xyColor = HSBType.fromXY(x, y);
|
HSBType xyColor = HSBType.fromXY(x, y);
|
||||||
colorValue.update(new HSBType(xyColor.getHue(), xyColor.getSaturation(), brightness));
|
colorValue.update(new HSBType(xyColor.getHue(), xyColor.getSaturation(), brightness));
|
||||||
}
|
}
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID),
|
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
|
||||||
colorValue.getChannelState());
|
|
||||||
return;
|
return;
|
||||||
case RGB_CHANNEL_ID:
|
case RGB_CHANNEL_ID:
|
||||||
colorValue.update((HSBType) state);
|
colorValue.update((HSBType) state);
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID),
|
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
|
||||||
colorValue.getChannelState());
|
|
||||||
break;
|
break;
|
||||||
case RGBW_CHANNEL_ID:
|
case RGBW_CHANNEL_ID:
|
||||||
case RGBWW_CHANNEL_ID:
|
case RGBWW_CHANNEL_ID:
|
||||||
|
|||||||
@ -65,8 +65,7 @@ public class DeviceTrigger extends AbstractComponent<DeviceTrigger.ChannelConfig
|
|||||||
value = new TextValue();
|
value = new TextValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
buildChannel(channelConfiguration.type, value, channelConfiguration.getName(),
|
buildChannel(channelConfiguration.type, value, getName(), componentConfiguration.getUpdateListener())
|
||||||
componentConfiguration.getUpdateListener())
|
|
||||||
.stateTopic(channelConfiguration.topic, channelConfiguration.getValueTemplate()).trigger(true).build();
|
.stateTopic(channelConfiguration.topic, channelConfiguration.getValueTemplate()).trigger(true).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,8 +54,7 @@ public class Fan extends AbstractComponent<Fan.ChannelConfiguration> {
|
|||||||
super(componentConfiguration, ChannelConfiguration.class);
|
super(componentConfiguration, ChannelConfiguration.class);
|
||||||
|
|
||||||
OnOffValue value = new OnOffValue(channelConfiguration.payloadOn, channelConfiguration.payloadOff);
|
OnOffValue value = new OnOffValue(channelConfiguration.payloadOn, channelConfiguration.payloadOff);
|
||||||
buildChannel(SWITCH_CHANNEL_ID, value, channelConfiguration.getName(),
|
buildChannel(SWITCH_CHANNEL_ID, value, getName(), componentConfiguration.getUpdateListener())
|
||||||
componentConfiguration.getUpdateListener())
|
|
||||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
||||||
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
||||||
channelConfiguration.getQos(), channelConfiguration.commandTemplate)
|
channelConfiguration.getQos(), channelConfiguration.commandTemplate)
|
||||||
|
|||||||
@ -286,12 +286,11 @@ public class JSONSchemaLight extends AbstractRawSchemaLight {
|
|||||||
colorModeValue.getChannelState());
|
colorModeValue.getChannelState());
|
||||||
|
|
||||||
if (hasColorChannel) {
|
if (hasColorChannel) {
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), COLOR_CHANNEL_ID), colorValue.getChannelState());
|
listener.updateChannelState(buildChannelUID(COLOR_CHANNEL_ID), colorValue.getChannelState());
|
||||||
} else if (brightnessChannel != null) {
|
} else if (brightnessChannel != null) {
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), BRIGHTNESS_CHANNEL_ID),
|
listener.updateChannelState(buildChannelUID(BRIGHTNESS_CHANNEL_ID), brightnessValue.getChannelState());
|
||||||
brightnessValue.getChannelState());
|
|
||||||
} else {
|
} else {
|
||||||
listener.updateChannelState(new ChannelUID(getGroupUID(), ON_OFF_CHANNEL_ID), onOffValue.getChannelState());
|
listener.updateChannelState(buildChannelUID(ON_OFF_CHANNEL_ID), onOffValue.getChannelState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,8 +58,8 @@ public class Lock extends AbstractComponent<Lock.ChannelConfiguration> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildChannel(SWITCH_CHANNEL_ID,
|
buildChannel(SWITCH_CHANNEL_ID,
|
||||||
new OnOffValue(channelConfiguration.payloadLock, channelConfiguration.payloadUnlock),
|
new OnOffValue(channelConfiguration.payloadLock, channelConfiguration.payloadUnlock), getName(),
|
||||||
channelConfiguration.getName(), componentConfiguration.getUpdateListener())
|
componentConfiguration.getUpdateListener())
|
||||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
||||||
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
||||||
channelConfiguration.getQos())
|
channelConfiguration.getQos())
|
||||||
|
|||||||
@ -82,8 +82,7 @@ public class Number extends AbstractComponent<Number.ChannelConfiguration> {
|
|||||||
NumberValue value = new NumberValue(channelConfiguration.min, channelConfiguration.max,
|
NumberValue value = new NumberValue(channelConfiguration.min, channelConfiguration.max,
|
||||||
channelConfiguration.step, UnitUtils.parseUnit(channelConfiguration.unitOfMeasurement));
|
channelConfiguration.step, UnitUtils.parseUnit(channelConfiguration.unitOfMeasurement));
|
||||||
|
|
||||||
buildChannel(NUMBER_CHANNEL_ID, value, channelConfiguration.getName(),
|
buildChannel(NUMBER_CHANNEL_ID, value, getName(), componentConfiguration.getUpdateListener())
|
||||||
componentConfiguration.getUpdateListener())
|
|
||||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
||||||
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
||||||
channelConfiguration.getQos(), channelConfiguration.commandTemplate)
|
channelConfiguration.getQos(), channelConfiguration.commandTemplate)
|
||||||
|
|||||||
@ -66,8 +66,7 @@ public class Select extends AbstractComponent<Select.ChannelConfiguration> {
|
|||||||
|
|
||||||
TextValue value = new TextValue(channelConfiguration.options);
|
TextValue value = new TextValue(channelConfiguration.options);
|
||||||
|
|
||||||
buildChannel(SELECT_CHANNEL_ID, value, channelConfiguration.getName(),
|
buildChannel(SELECT_CHANNEL_ID, value, getName(), componentConfiguration.getUpdateListener())
|
||||||
componentConfiguration.getUpdateListener())
|
|
||||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())
|
||||||
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
.commandTopic(channelConfiguration.commandTopic, channelConfiguration.isRetain(),
|
||||||
channelConfiguration.getQos(), channelConfiguration.commandTemplate)
|
channelConfiguration.getQos(), channelConfiguration.commandTemplate)
|
||||||
|
|||||||
@ -88,8 +88,7 @@ public class Sensor extends AbstractComponent<Sensor.ChannelConfiguration> {
|
|||||||
|
|
||||||
boolean trigger = TRIGGER_ICONS.matcher(icon).matches();
|
boolean trigger = TRIGGER_ICONS.matcher(icon).matches();
|
||||||
|
|
||||||
buildChannel(SENSOR_CHANNEL_ID, value, channelConfiguration.getName(),
|
buildChannel(SENSOR_CHANNEL_ID, value, getName(), getListener(componentConfiguration, value))
|
||||||
getListener(componentConfiguration, value))
|
|
||||||
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())//
|
.stateTopic(channelConfiguration.stateTopic, channelConfiguration.getValueTemplate())//
|
||||||
.trigger(trigger).build();
|
.trigger(trigger).build();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -294,7 +294,7 @@ public class Vacuum extends AbstractComponent<Vacuum.ChannelConfiguration> {
|
|||||||
ChannelStateUpdateListener channelStateUpdateListener, @Nullable String commandTemplate,
|
ChannelStateUpdateListener channelStateUpdateListener, @Nullable String commandTemplate,
|
||||||
@Nullable String commandTopic, @Nullable String stateTemplate, @Nullable String stateTopic) {
|
@Nullable String commandTopic, @Nullable String stateTemplate, @Nullable String stateTopic) {
|
||||||
if ((commandTopic != null && !commandTopic.isBlank()) || (stateTopic != null && !stateTopic.isBlank())) {
|
if ((commandTopic != null && !commandTopic.isBlank()) || (stateTopic != null && !stateTopic.isBlank())) {
|
||||||
return buildChannel(channelId, valueState, channelConfiguration.getName(), channelStateUpdateListener)
|
return buildChannel(channelId, valueState, getName(), channelStateUpdateListener)
|
||||||
.stateTopic(stateTopic, stateTemplate, channelConfiguration.getValueTemplate())
|
.stateTopic(stateTopic, stateTemplate, channelConfiguration.getValueTemplate())
|
||||||
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos(),
|
.commandTopic(commandTopic, channelConfiguration.isRetain(), channelConfiguration.getQos(),
|
||||||
commandTemplate)
|
commandTemplate)
|
||||||
|
|||||||
@ -33,8 +33,9 @@ import com.google.gson.annotations.SerializedName;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public abstract class AbstractChannelConfiguration {
|
public abstract class AbstractChannelConfiguration {
|
||||||
public static final char PARENT_TOPIC_PLACEHOLDER = '~';
|
public static final char PARENT_TOPIC_PLACEHOLDER = '~';
|
||||||
|
private static final String DEFAULT_THING_NAME = "Home Assistant Device";
|
||||||
|
|
||||||
protected String name;
|
protected @Nullable String name;
|
||||||
|
|
||||||
protected String icon = "";
|
protected String icon = "";
|
||||||
protected int qos; // defaults to 0 according to HA specification
|
protected int qos; // defaults to 0 according to HA specification
|
||||||
@ -93,6 +94,9 @@ public abstract class AbstractChannelConfiguration {
|
|||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = name;
|
result = name;
|
||||||
}
|
}
|
||||||
|
if (result == null) {
|
||||||
|
result = DEFAULT_THING_NAME;
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +131,7 @@ public abstract class AbstractChannelConfiguration {
|
|||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public @Nullable String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@ -44,6 +45,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.config.ChannelConfigurati
|
|||||||
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
import org.openhab.binding.mqtt.homeassistant.internal.exception.ConfigurationException;
|
||||||
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
|
import org.openhab.core.thing.ChannelGroupUID;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
@ -53,7 +55,6 @@ import org.openhab.core.thing.ThingUID;
|
|||||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||||
import org.openhab.core.thing.type.ChannelDefinition;
|
import org.openhab.core.thing.type.ChannelDefinition;
|
||||||
import org.openhab.core.thing.type.ChannelGroupDefinition;
|
import org.openhab.core.thing.type.ChannelGroupDefinition;
|
||||||
import org.openhab.core.thing.type.ChannelGroupType;
|
|
||||||
import org.openhab.core.thing.type.ThingType;
|
import org.openhab.core.thing.type.ThingType;
|
||||||
import org.openhab.core.thing.util.ThingHelper;
|
import org.openhab.core.thing.util.ThingHelper;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -93,7 +94,7 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
protected final DiscoverComponents discoverComponents;
|
protected final DiscoverComponents discoverComponents;
|
||||||
|
|
||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
protected final Map<String, AbstractComponent<?>> haComponents = new HashMap<>();
|
protected final Map<@Nullable String, AbstractComponent<?>> haComponents = new HashMap<>();
|
||||||
|
|
||||||
protected HandlerConfiguration config = new HandlerConfiguration();
|
protected HandlerConfiguration config = new HandlerConfiguration();
|
||||||
private Set<HaID> discoveryHomeAssistantIDs = new HashSet<>();
|
private Set<HaID> discoveryHomeAssistantIDs = new HashSet<>();
|
||||||
@ -137,10 +138,6 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
|
|
||||||
for (Channel channel : thing.getChannels()) {
|
for (Channel channel : thing.getChannels()) {
|
||||||
final String groupID = channel.getUID().getGroupId();
|
final String groupID = channel.getUID().getGroupId();
|
||||||
if (groupID == null) {
|
|
||||||
logger.warn("Channel {} has no groupd ID", channel.getLabel());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Already restored component?
|
// Already restored component?
|
||||||
@Nullable
|
@Nullable
|
||||||
AbstractComponent<?> component = haComponents.get(groupID);
|
AbstractComponent<?> component = haComponents.get(groupID);
|
||||||
@ -160,7 +157,12 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
try {
|
try {
|
||||||
component = ComponentFactory.createComponent(thingUID, haID, channelConfigurationJSON, this, this,
|
component = ComponentFactory.createComponent(thingUID, haID, channelConfigurationJSON, this, this,
|
||||||
scheduler, gson, transformationServiceProvider);
|
scheduler, gson, transformationServiceProvider);
|
||||||
haComponents.put(component.getGroupUID().getId(), component);
|
final ChannelGroupUID groupUID = component.getGroupUID();
|
||||||
|
String id = null;
|
||||||
|
if (groupUID != null) {
|
||||||
|
id = groupUID.getId();
|
||||||
|
}
|
||||||
|
haComponents.put(id, component);
|
||||||
component.addChannelTypes(channelTypeProvider);
|
component.addChannelTypes(channelTypeProvider);
|
||||||
} catch (ConfigurationException e) {
|
} catch (ConfigurationException e) {
|
||||||
logger.error("Cannot not restore component {}: {}", thing, e.getMessage());
|
logger.error("Cannot not restore component {}: {}", thing, e.getMessage());
|
||||||
@ -228,9 +230,6 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
@Override
|
@Override
|
||||||
public @Nullable ChannelState getChannelState(ChannelUID channelUID) {
|
public @Nullable ChannelState getChannelState(ChannelUID channelUID) {
|
||||||
String groupID = channelUID.getGroupId();
|
String groupID = channelUID.getGroupId();
|
||||||
if (groupID == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
AbstractComponent<?> component;
|
AbstractComponent<?> component;
|
||||||
synchronized (haComponents) { // sync whenever discoverComponents is started
|
synchronized (haComponents) { // sync whenever discoverComponents is started
|
||||||
component = haComponents.get(groupID);
|
component = haComponents.get(groupID);
|
||||||
@ -266,7 +265,12 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
|
|
||||||
synchronized (haComponents) { // sync whenever discoverComponents is started
|
synchronized (haComponents) { // sync whenever discoverComponents is started
|
||||||
for (AbstractComponent<?> discovered : discoveredComponentsList) {
|
for (AbstractComponent<?> discovered : discoveredComponentsList) {
|
||||||
AbstractComponent<?> known = haComponents.get(discovered.getGroupUID().getId());
|
final ChannelGroupUID groupUID = discovered.getGroupUID();
|
||||||
|
String id = null;
|
||||||
|
if (groupUID != null) {
|
||||||
|
id = groupUID.getId();
|
||||||
|
}
|
||||||
|
AbstractComponent<?> known = haComponents.get(id);
|
||||||
// Is component already known?
|
// Is component already known?
|
||||||
if (known != null) {
|
if (known != null) {
|
||||||
if (discovered.getConfigHash() != known.getConfigHash()) {
|
if (discovered.getConfigHash() != known.getConfigHash()) {
|
||||||
@ -282,10 +286,10 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
// Add channel and group types to the types registry
|
// Add channel and group types to the types registry
|
||||||
discovered.addChannelTypes(channelTypeProvider);
|
discovered.addChannelTypes(channelTypeProvider);
|
||||||
// Add component to the component map
|
// Add component to the component map
|
||||||
haComponents.put(discovered.getGroupUID().getId(), discovered);
|
haComponents.put(id, discovered);
|
||||||
// Start component / Subscribe to channel topics
|
// Start component / Subscribe to channel topics
|
||||||
discovered.start(connection, scheduler, 0).exceptionally(e -> {
|
discovered.start(connection, scheduler, 0).exceptionally(e -> {
|
||||||
logger.warn("Failed to start component {}", discovered.getGroupUID(), e);
|
logger.warn("Failed to start component {}", discovered.getHaID(), e);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -296,7 +300,7 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
// We remove all conflicting old channels, they will be re-added below based on the new discovery
|
// We remove all conflicting old channels, they will be re-added below based on the new discovery
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Received component {} with slightly different config. Making sure we re-create conflicting channels...",
|
"Received component {} with slightly different config. Making sure we re-create conflicting channels...",
|
||||||
discovered.getGroupUID());
|
discovered.getHaID());
|
||||||
removeJustRediscoveredChannels(discoveredChannels);
|
removeJustRediscoveredChannels(discoveredChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,9 +350,8 @@ public class HomeAssistantThingHandler extends AbstractMQTTThingHandler
|
|||||||
List<ChannelDefinition> channelDefs;
|
List<ChannelDefinition> channelDefs;
|
||||||
synchronized (haComponents) { // sync whenever discoverComponents is started
|
synchronized (haComponents) { // sync whenever discoverComponents is started
|
||||||
groupDefs = haComponents.values().stream().map(AbstractComponent::getGroupDefinition)
|
groupDefs = haComponents.values().stream().map(AbstractComponent::getGroupDefinition)
|
||||||
.collect(Collectors.toList());
|
.filter(Objects::nonNull).map(Objects::requireNonNull).collect(Collectors.toList());
|
||||||
channelDefs = haComponents.values().stream().map(AbstractComponent::getType)
|
channelDefs = haComponents.values().stream().map(AbstractComponent::getChannels).flatMap(List::stream)
|
||||||
.map(ChannelGroupType::getChannelDefinitions).flatMap(List::stream)
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
ThingType thingType = channelTypeProvider.derive(typeID, MqttBindingConstants.HOMEASSISTANT_MQTT_THING)
|
ThingType thingType = channelTypeProvider.derive(typeID, MqttBindingConstants.HOMEASSISTANT_MQTT_THING)
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@ -160,7 +161,8 @@ public class HomeAssistantMQTTImplementationTest extends MqttOSGiTest {
|
|||||||
ComponentDiscovered cd = (haID, c) -> {
|
ComponentDiscovered cd = (haID, c) -> {
|
||||||
haComponents.put(c.getGroupUID().getId(), c);
|
haComponents.put(c.getGroupUID().getId(), c);
|
||||||
c.addChannelTypes(channelTypeProvider);
|
c.addChannelTypes(channelTypeProvider);
|
||||||
channelTypeProvider.setChannelGroupType(c.getGroupTypeUID(), c.getType());
|
channelTypeProvider.setChannelGroupType(Objects.requireNonNull(c.getGroupTypeUID()),
|
||||||
|
Objects.requireNonNull(c.getType()));
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user