Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[insteon] Refactor msg definition/factory and product data classes #17537

Merged
merged 1 commit into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
import org.openhab.binding.insteon.internal.device.X10Address;
import org.openhab.binding.insteon.internal.device.X10Device;
import org.openhab.binding.insteon.internal.transport.PortListener;
import org.openhab.binding.insteon.internal.transport.message.Direction;
import org.openhab.binding.insteon.internal.transport.message.FieldException;
import org.openhab.binding.insteon.internal.transport.message.InvalidMessageTypeException;
import org.openhab.binding.insteon.internal.transport.message.Msg;
import org.openhab.binding.insteon.internal.transport.message.Msg.Direction;
import org.openhab.binding.insteon.internal.transport.message.MsgDefinitionRegistry;
import org.openhab.binding.insteon.internal.utils.HexUtils;
import org.openhab.core.io.console.Console;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ private void handleModemInfo(Msg msg) throws FieldException {
int deviceCategory = msg.getInt("DeviceCategory");
int subCategory = msg.getInt("DeviceSubCategory");

ProductData productData = ProductDataRegistry.getInstance().getProductData(deviceCategory, subCategory);
ProductData productData = ProductData.makeInsteonProduct(deviceCategory, subCategory);
productData.setFirmwareVersion(msg.getInt("FirmwareVersion"));

DeviceType deviceType = productData.getDeviceType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ public List<DeviceFeature> getFeatures(InsteonAddress address) {
}

public State getState() {
return getEntries().stream().allMatch(entry -> entry.getState() == UnDefType.NULL) ? UnDefType.NULL
: OnOffType.from(getEntries().stream().filter(entry -> entry.getState() != UnDefType.NULL)
.allMatch(entry -> entry.getState().equals(entry.getOnState())));
return getEntries().stream().noneMatch(SceneEntry::isStateDefined) ? UnDefType.NULL
: OnOffType
.from(getEntries().stream().filter(SceneEntry::isStateDefined).allMatch(SceneEntry::isStateOn));
}

public boolean hasEntry(InsteonAddress address) {
Expand Down Expand Up @@ -354,6 +354,14 @@ public State getState() {
return state;
}

public boolean isStateDefined() {
return !UnDefType.NULL.equals(state);
}

public boolean isStateOn() {
return getOnState().equals(state);
}

public void setState(State state) {
this.state = state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,21 +231,9 @@ public static ProductData makeInsteonProduct(int deviceCategory, int subCategory
ProductData productData = new ProductData();
productData.setDeviceCategory(deviceCategory);
productData.setSubCategory(subCategory);
return productData;
}

/**
* Factory method for creating a ProductData for an Insteon product
*
* @param deviceCategory the Insteon device category
* @param subCategory the Insteon device subcategory
* @param srcData the source product data to use
* @return the product data
*/
public static ProductData makeInsteonProduct(int deviceCategory, int subCategory, @Nullable ProductData srcData) {
ProductData productData = makeInsteonProduct(deviceCategory, subCategory);
if (srcData != null) {
productData.update(srcData);
ProductData resourceData = ProductDataRegistry.getInstance().getProductData(deviceCategory, subCategory);
if (resourceData != null) {
productData.update(resourceData);
}
return productData;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,17 @@ private ProductDataRegistry() {
*
* @param deviceCategory device category to match
* @param subCategory device subcategory to match
* @return product data matching provided parameters
* @return product data if matching provided parameters, otherwise null
*/
public ProductData getProductData(int deviceCategory, int subCategory) {
public @Nullable ProductData getProductData(int deviceCategory, int subCategory) {
int productId = getProductId(deviceCategory, subCategory);
if (!products.containsKey(productId)) {
logger.warn("unknown product for devCat:{} subCat:{} in device products xml file",
HexUtils.getHexString(deviceCategory), HexUtils.getHexString(subCategory));
// fallback to matching product id using device category only
productId = getProductId(deviceCategory, ProductData.SUB_CATEGORY_UNKNOWN);
}

return ProductData.makeInsteonProduct(deviceCategory, subCategory, products.get(productId));
}

/**
* Returns the device type for a given dev/sub category
*
* @param deviceCategory device category to match
* @param subCategory device subcategory to match
* @return device type matching provided parameters
*/
public @Nullable DeviceType getDeviceType(int deviceCategory, int subCategory) {
return getProductData(deviceCategory, subCategory).getDeviceType();
return products.get(productId);
}

/**
Expand Down Expand Up @@ -143,7 +131,9 @@ private void parseProduct(Element element) throws SAXException {
logger.warn("overwriting previous definition of product {}", products.get(productId));
}

ProductData productData = ProductData.makeInsteonProduct(deviceCategory, subCategory);
ProductData productData = new ProductData();
productData.setDeviceCategory(deviceCategory);
productData.setSubCategory(subCategory);
productData.setProductKey(productKey);
productData.setFirstRecordLocation(firstRecord);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -64,6 +65,8 @@ public enum RampRate {
SEC_0_2(0x1E, 0.2),
INSTANT(0x1F, 0.1);

private static final List<String> SUPPORTED_FEATURE_TYPES = List.of(FEATURE_TYPE_GENERIC_DIMMER);

private static final Map<Integer, RampRate> VALUE_MAP = Arrays.stream(values())
.collect(Collectors.toUnmodifiableMap(rate -> rate.value, Function.identity()));

Expand Down Expand Up @@ -105,7 +108,7 @@ public String toString() {
* @return true if supported
*/
public static boolean supportsFeatureType(String featureType) {
return FEATURE_TYPE_GENERIC_DIMMER.equals(featureType);
return SUPPORTED_FEATURE_TYPES.contains(featureType);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.openhab.binding.insteon.internal.device.InsteonAddress;
import org.openhab.binding.insteon.internal.device.InsteonModem;
import org.openhab.binding.insteon.internal.device.ProductData;
import org.openhab.binding.insteon.internal.device.ProductDataRegistry;
import org.openhab.binding.insteon.internal.transport.PortListener;
import org.openhab.binding.insteon.internal.transport.message.FieldException;
import org.openhab.binding.insteon.internal.transport.message.InvalidMessageTypeException;
Expand Down Expand Up @@ -290,7 +289,7 @@ private void handleProductData(Msg msg) throws FieldException {
int subCategory = Byte.toUnsignedInt(toAddr.getMiddleByte());
int firmware = Byte.toUnsignedInt(toAddr.getLowByte());
int hardware = msg.getInt("command2");
ProductData productData = ProductDataRegistry.getInstance().getProductData(deviceCategory, subCategory);
ProductData productData = ProductData.makeInsteonProduct(deviceCategory, subCategory);
productData.setFirmwareVersion(firmware);
productData.setHardwareVersion(hardware);
// set product data if in modem db
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ protected void startScan() {

public void discoverInsteonDevice(InsteonAddress address, @Nullable ProductData productData) {
InsteonModem modem = handler.getModem();
if (handler.isDeviceDiscoveryEnabled() && modem != null && modem.getDB().hasEntry(address)
&& !modem.hasDevice(address)) {
if (modem != null && modem.getDB().hasEntry(address) && !modem.hasDevice(address)) {
addInsteonDevice(address, productData);
} else {
removeInsteonDevice(address);
Expand All @@ -72,8 +71,7 @@ public void discoverInsteonDevice(InsteonAddress address, @Nullable ProductData

public void discoverInsteonScene(int group) {
InsteonModem modem = handler.getModem();
if (handler.isSceneDiscoveryEnabled() && modem != null && modem.getDB().hasBroadcastGroup(group)
&& !modem.hasScene(group)) {
if (modem != null && modem.getDB().hasBroadcastGroup(group) && !modem.hasScene(group)) {
addInsteonScene(group);
} else {
removeInsteonScene(group);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,14 @@ private void cleanUpStorage(InsteonAddress address) {

protected void discoverInsteonDevice(InsteonAddress address, @Nullable ProductData productData) {
InsteonDiscoveryService discoveryService = getDiscoveryService();
if (discoveryService != null) {
if (discoveryService != null && isDeviceDiscoveryEnabled()) {
scheduler.execute(() -> discoveryService.discoverInsteonDevice(address, productData));
}
}

protected void discoverInsteonScene(int group) {
InsteonDiscoveryService discoveryService = getDiscoveryService();
if (discoveryService != null) {
if (discoveryService != null && isSceneDiscoveryEnabled()) {
scheduler.execute(() -> discoveryService.discoverInsteonScene(group));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.stream.Collectors;

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

/**
* Defines the data types that can be used in the fields of a message.
Expand All @@ -29,8 +30,7 @@
@NonNullByDefault
public enum DataType {
BYTE("byte", 1),
ADDRESS("address", 3),
INVALID("invalid", -1);
ADDRESS("address", 3);

private static final Map<String, DataType> NAME_MAP = Arrays.stream(values())
.collect(Collectors.toUnmodifiableMap(type -> type.name, Function.identity()));
Expand All @@ -55,9 +55,9 @@ public int getSize() {
* Factory method for getting a DataType from the data type name
*
* @param name the data type name
* @return the data type
* @return the data type if defined, otherwise null
*/
public static DataType get(String name) {
return NAME_MAP.getOrDefault(name, DataType.INVALID);
public static @Nullable DataType get(String name) {
return NAME_MAP.get(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* 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.insteon.internal.transport.message;

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

/**
* The {@link Direction} represents a message direction
*
* @author Jeremy Setton - Initial contribution
*/
@NonNullByDefault
public enum Direction {
FROM_MODEM("IN"),
TO_MODEM("OUT");

private final String label;

private Direction(String label) {
this.label = label;
}

@Override
public String toString() {
return label;
}

public static @Nullable Direction get(String value) {
try {
return Direction.valueOf(value);
} catch (IllegalArgumentException e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ public final class Field {
private final int offset;
private final DataType type;

public Field(String name, int offset, DataType type) {
this.name = name;
this.offset = offset;
this.type = type;
}

public String getName() {
return name;
}
Expand All @@ -42,16 +48,6 @@ public int getOffset() {
return offset;
}

public DataType getType() {
return type;
}

public Field(String name, DataType type, int offset) {
this.name = name;
this.type = type;
this.offset = offset;
}

private void check(int len, DataType t) throws FieldException {
if (offset + type.getSize() > len) {
throw new FieldException("field write beyond end of msg");
Expand All @@ -61,16 +57,16 @@ private void check(int len, DataType t) throws FieldException {
}
}

public void set(byte[] data, Object o) throws FieldException {
public void set(byte[] data, String value) throws FieldException, IllegalArgumentException {
switch (type) {
case BYTE:
setByte(data, (Byte) o);
byte b = value.isEmpty() ? 0x00 : (byte) HexUtils.toInteger(value);
setByte(data, b);
break;
case ADDRESS:
setAddress(data, (InsteonAddress) o);
InsteonAddress address = value.isEmpty() ? InsteonAddress.UNKNOWN : new InsteonAddress(value);
setAddress(data, address);
break;
default:
throw new FieldException("field data type unknown");
}
}

Expand Down Expand Up @@ -141,8 +137,6 @@ public String toString(byte[] data) {
case ADDRESS:
s += getAddress(data).toString();
break;
default:
throw new FieldException("field data type unknown");
}
} catch (FieldException e) {
s += "NULL";
Expand Down
Loading