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

Only restore attribute state from the node database for non-manufacturer-specific attributes #1001

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 @@ -543,6 +543,17 @@ public void setDao(ZclCluster cluster, ZclAttributeDao dao) {
reportingTimeout = dao.getReportingTimeout();
manufacturerCode = dao.getManufacturerCode();
}

/**
* Sets the dynamic state of the attribute from a {@link ZclAttributeDao} which has been restored from a persisted state.
*
* @param dao the {@link ZclAttributeDao} from which to restore the dynamic state
*/
public void setDynamicStateFromDao(ZclAttributeDao dao) {
implemented = dao.isImplemented();
lastValue = dao.getLastValue();
lastReportTime = dao.getLastReportTime();
}

/**
* Returns a Data Acquisition Object for this attribute. This is a clean class recording the state of the primary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,14 @@ public abstract class ZclCluster {

/**
* Map of client attributes supported by the cluster. This contains all attributes, even if they are not supported
* by the remote device. To check what attributes are supported by the remove device, us the
* by the remote device. To check what attributes are supported by the remove device, use the
* {@link #discoverAttributes()} method followed by the {@link #getSupportedAttributes()} method.
*/
protected Map<Integer, ZclAttribute> clientAttributes = initializeClientAttributes();

/**
* Map of server attributes supported by the cluster. This contains all attributes, even if they are not supported
* by the remote device. To check what attributes are supported by the remove device, us the
* by the remote device. To check what attributes are supported by the remove device, use the
* {@link #discoverAttributes()} method followed by the {@link #getSupportedAttributes()} method.
*/
protected Map<Integer, ZclAttribute> serverAttributes = initializeServerAttributes();
Expand Down Expand Up @@ -1598,20 +1598,21 @@ public void setDao(ZclClusterDao dao) {
supportedCommandsGenerated.addAll(dao.getSupportedCommandsGenerated());
supportedCommandsReceived.addAll(dao.getSupportedCommandsReceived());

Map<Integer, ZclAttribute> daoZclAttributes = new HashMap<>();
Map<Integer, ZclAttribute> attributes = isClient ? clientAttributes : serverAttributes;

for (ZclAttributeDao daoAttribute : dao.getAttributes().values()) {
// Normalize the data to protect against the users serialisation system restoring incorrect data classes
daoAttribute
.setLastValue(normalizer.normalizeZclData(daoAttribute.getDataType(), daoAttribute.getLastValue()));
ZclAttribute attribute = new ZclAttribute();
attribute.setDao(this, daoAttribute);
daoZclAttributes.put(daoAttribute.getId(), attribute);
}

if (isClient) {
clientAttributes = daoZclAttributes;
} else {
serverAttributes = daoZclAttributes;

ZclAttribute attribute = attributes.get(daoAttribute.getId());
if (attribute == null || daoAttribute.getManufacturerCode() != null) {
attribute = new ZclAttribute();
attribute.setDao(this, daoAttribute);
attributes.put(daoAttribute.getId(), attribute);
} else {
attribute.setDynamicStateFromDao(daoAttribute);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
*/
package com.zsmartsystems.zigbee.zcl;

import static com.zsmartsystems.zigbee.zcl.clusters.ZclOnOffCluster.ATTR_ONOFF;
import static java.lang.Boolean.TRUE;
import static java.util.stream.Collectors.toSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
Expand All @@ -15,7 +18,6 @@

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -652,22 +654,54 @@ record = records.get(1);

@Test
public void setDao() {
// Given an On/Off cluster and the DAO created from that cluster
createEndpoint();

ZclOnOffCluster cluster = new ZclOnOffCluster(endpoint);
Set<Integer> onOffClusterAttributeIds = cluster.getAttributes().stream().map(ZclAttribute::getId)
.collect(toSet());

ZclClusterDao clusterDao = cluster.getDao();
ZclAttributeDao attributeDao = new ZclAttributeDao();
attributeDao.setDataType(ZclDataType.SIGNED_16_BIT_INTEGER);
attributeDao.setId(1);
attributeDao.setLastValue(Double.valueOf(123));
Map<Integer, ZclAttributeDao> attributes = new HashMap<>();
attributes.put(1, attributeDao);
clusterDao.setAttributes(attributes);
Map<Integer, ZclAttributeDao> attributeDaos = clusterDao.getAttributes();

// Add one attribute for a manufacturer-specific attribute to the DAO
ZclAttributeDao manufacturerSpecificAttributeDao = new ZclAttributeDao();
manufacturerSpecificAttributeDao.setId(0xF000);
manufacturerSpecificAttributeDao.setManufacturerCode(0x1234);
manufacturerSpecificAttributeDao.setDataType(ZclDataType.SIGNED_16_BIT_INTEGER);
manufacturerSpecificAttributeDao.setLastValue(Double.valueOf(123));
attributeDaos.put(manufacturerSpecificAttributeDao.getId(), manufacturerSpecificAttributeDao);

// Set last value and implemented status for the on/off attribute in the DAO
ZclAttributeDao onOffAttributeDao = attributeDaos.get(ATTR_ONOFF);
onOffAttributeDao.setLastValue(TRUE);
onOffAttributeDao.setImplemented(true);

clusterDao.setAttributes(attributeDaos);

// Now update the cluster from the DAO
cluster.setDao(clusterDao);
assertEquals(1, cluster.getAttributes().size());
assertEquals(Integer.class, cluster.getAttributes().iterator().next().getLastValue().getClass());

// Then the cluster contains all attributes from the on/off cluster, plus the manufacturer-specific attribute
assertEquals(onOffClusterAttributeIds.size() + 1, cluster.getAttributes().size());
for (Integer attributeId : onOffClusterAttributeIds) {
ZclAttribute attribute = cluster.getAttribute(attributeId);
assertNotNull(attribute);
assertEquals(new ZclOnOffCluster(endpoint).getAttribute(attributeId).getDataType(),
attribute.getDataType());
assertEquals(new ZclOnOffCluster(endpoint).getAttribute(attributeId).getMaximumReportingPeriod(),
attribute.getMaximumReportingPeriod());
assertEquals(new ZclOnOffCluster(endpoint).getAttribute(attributeId).getName(), attribute.getName());
}

// The onOff attribute has the state set correctly
ZclAttribute onOffAttribute = cluster.getAttribute(ATTR_ONOFF);
assertEquals(TRUE, onOffAttribute.getLastValue());
assertTrue(onOffAttribute.isImplemented());

// And the manufacturer-specific attribute has the state set correctly
ZclAttribute manufacturerSpecificAttribute = cluster.getAttribute(0xF000);
assertEquals(manufacturerSpecificAttribute.getManufacturerCode(), Integer.valueOf(0x1234));
assertEquals(manufacturerSpecificAttribute.getLastValue(), Integer.valueOf(123));
}

@Test
Expand Down