Skip to content

Commit

Permalink
[miio] dynamically generate channelTypes
Browse files Browse the repository at this point in the history
Simplify the json database creation for new models and less chance for
errors
Related to openhab#7276

Signed-off-by: Marcel Verpaalen <marcel@verpaalen.com>
  • Loading branch information
marcelrv committed Nov 28, 2020
1 parent 219d370 commit ec5cb18
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.miio.internal.basic.BasicChannelTypeProvider;
import org.openhab.binding.miio.internal.basic.MiIoDatabaseWatchService;
import org.openhab.binding.miio.internal.cloud.CloudConnector;
import org.openhab.binding.miio.internal.handler.MiIoBasicHandler;
Expand Down Expand Up @@ -52,11 +53,12 @@ public class MiIoHandlerFactory extends BaseThingHandlerFactory {
private MiIoDatabaseWatchService miIoDatabaseWatchService;
private CloudConnector cloudConnector;
private ChannelTypeRegistry channelTypeRegistry;
private BasicChannelTypeProvider basicChannelTypeProvider;

@Activate
public MiIoHandlerFactory(@Reference ChannelTypeRegistry channelTypeRegistry,
@Reference MiIoDatabaseWatchService miIoDatabaseWatchService, @Reference CloudConnector cloudConnector,
Map<String, Object> properties) {
@Reference BasicChannelTypeProvider basicChannelTypeProvider, Map<String, Object> properties) {
this.miIoDatabaseWatchService = miIoDatabaseWatchService;
this.cloudConnector = cloudConnector;
@Nullable
Expand All @@ -68,6 +70,7 @@ public MiIoHandlerFactory(@Reference ChannelTypeRegistry channelTypeRegistry,
cloudConnector.setCredentials(username, password, country);
scheduler.submit(() -> cloudConnector.isConnected());
this.channelTypeRegistry = channelTypeRegistry;
this.basicChannelTypeProvider = basicChannelTypeProvider;
}

@Override
Expand All @@ -82,7 +85,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return new MiIoGenericHandler(thing, miIoDatabaseWatchService);
}
if (thingTypeUID.equals(THING_TYPE_BASIC)) {
return new MiIoBasicHandler(thing, miIoDatabaseWatchService, channelTypeRegistry);
return new MiIoBasicHandler(thing, miIoDatabaseWatchService, channelTypeRegistry, basicChannelTypeProvider);
}
if (thingTypeUID.equals(THING_TYPE_VACUUM)) {
return new MiIoVacuumHandler(thing, miIoDatabaseWatchService, cloudConnector, channelTypeRegistry);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Copyright (c) 2010-2020 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.miio.internal.basic;

import static org.openhab.binding.miio.internal.MiIoBindingConstants.BINDING_ID;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeBuilder;
import org.openhab.core.thing.type.ChannelTypeProvider;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.thing.type.StateChannelTypeBuilder;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.openhab.core.types.StateOption;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Provide channelTypes for Mi IO Basic devices
*
* @author Marcel Verpaalen - Initial contribution
*/
@Component(service = { ChannelTypeProvider.class, BasicChannelTypeProvider.class })
@NonNullByDefault
public class BasicChannelTypeProvider implements ChannelTypeProvider {
private final List<ChannelType> channelTypes = new CopyOnWriteArrayList<>();
private final Logger logger = LoggerFactory.getLogger(BasicChannelTypeProvider.class);

@Override
public Collection<ChannelType> getChannelTypes(@Nullable Locale locale) {
return channelTypes;
}

@Override
public @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID, @Nullable Locale locale) {
for (ChannelType channelType : channelTypes) {
if (channelType.getUID().equals(channelTypeUID)) {
return channelType;
}
}
return null;
}

public void addChannelType(MiIoBasicChannel miChannel, String model) {
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID,
model.toUpperCase().replace(".", "_") + "_" + miChannel.getChannel());
logger.debug("Adding channel definitions for {} -> {}", channelTypeUID, miChannel.getFriendlyName());
try {
final StateDescriptionDTO stateDescription = miChannel.getStateDescription();
StateChannelTypeBuilder channelTypeBuilder = ChannelTypeBuilder.state(channelTypeUID,
miChannel.getFriendlyName(), miChannel.getType()); //
if (stateDescription != null) {
StateDescriptionFragmentBuilder sdf = StateDescriptionFragmentBuilder.create();
final BigDecimal maximum = stateDescription.getMaximum();
if (maximum != null) {
sdf.withMaximum(maximum);
}
final BigDecimal minimum = stateDescription.getMinimum();
if (minimum != null) {
sdf.withMinimum(minimum);
}
final BigDecimal step = stateDescription.getStep();
if (step != null) {
sdf.withStep(step);
}
final String pattern = stateDescription.getPattern();
if (pattern != null) {
sdf.withPattern(pattern);
}
final Boolean readOnly = stateDescription.getReadOnly();
if (readOnly != null) {
sdf.withReadOnly(readOnly);
}
List<OptionsValueListDTO> optionList = stateDescription.getOptions();
if (optionList != null) {
List<StateOption> options = new ArrayList<>();
for (OptionsValueListDTO option : optionList) {
String value = option.getValue();
if (value != null) {
options.add(new StateOption(value, option.getDescription()));
}
}
sdf.withOptions(options);
}
channelTypeBuilder.withStateDescriptionFragment(sdf.build());
logger.debug("added stateDescription: {}", sdf);
}
channelTypes.add(channelTypeBuilder.build());
} catch (

Exception ex) {
logger.warn("Failed creating channelType {}: {}", channelTypeUID, ex.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public class MiIoBasicChannel {
@SerializedName("unit")
@Expose
private @Nullable String unit;
@SerializedName("stateDescription")
@Expose
private @Nullable StateDescriptionDTO stateDescription;
@SerializedName("refresh")
@Expose
private @Nullable Boolean refresh;
Expand Down Expand Up @@ -167,6 +170,14 @@ public void setUnit(String unit) {
this.unit = unit;
}

public @Nullable StateDescriptionDTO getStateDescription() {
return stateDescription;
}

public void setStateDescription(@Nullable StateDescriptionDTO stateDescription) {
this.stateDescription = stateDescription;
}

public Boolean getRefresh() {
final @Nullable Boolean rf = refresh;
return rf != null && rf.booleanValue() && !getProperty().isEmpty();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2020 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.miio.internal.basic;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

/**
* Mapping properties from json for miot device info
*
* @author Marcel Verpaalen - Initial contribution
*/
@NonNullByDefault
public class OptionsValueListDTO {

@SerializedName("value")
@Expose
@Nullable
public String value;
@SerializedName("description")
@Expose
@Nullable
public String description;

@Nullable
public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

@Nullable
public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* Copyright (c) 2010-2020 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.miio.internal.basic;

import java.math.BigDecimal;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

/**
* Mapping properties from json for state descriptions
*
* @author Marcel Verpaalen - Initial contribution
*/
@NonNullByDefault
public class StateDescriptionDTO {

@SerializedName("minimum")
@Expose
@Nullable
private BigDecimal minimum;
@SerializedName("maximum")
@Expose
@Nullable
private BigDecimal maximum;
@SerializedName("step")
@Expose
@Nullable
private BigDecimal step;
@SerializedName("pattern")
@Expose
@Nullable
private String pattern;
@SerializedName("readOnly")
@Expose
@Nullable
private Boolean readOnly;
@SerializedName("options")
@Expose
@Nullable
public List<OptionsValueListDTO> options = null;

@Nullable
public BigDecimal getMinimum() {
return minimum;
}

public void setMinimum(BigDecimal minimum) {
this.minimum = minimum;
}

@Nullable
public BigDecimal getMaximum() {
return maximum;
}

public void setMaximum(BigDecimal maximum) {
this.maximum = maximum;
}

@Nullable
public BigDecimal getStep() {
return step;
}

public void setStep(BigDecimal step) {
this.step = step;
}

@Nullable
public String getPattern() {
return pattern;
}

public void setPattern(String pattern) {
this.pattern = pattern;
}

@Nullable
public Boolean getReadOnly() {
return readOnly;
}

public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}

@Nullable
public List<OptionsValueListDTO> getOptions() {
return options;
}

public void setOptions(List<OptionsValueListDTO> options) {
this.options = options;
}
}
Loading

0 comments on commit ec5cb18

Please sign in to comment.