diff --git a/.gitignore b/.gitignore index ccb0a126f0..0e728e385f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ target/ bin/ -database/ *.iml *.log *.log.* @@ -33,6 +32,9 @@ simple-network.xml *.gbl *.s37 +com.zsmartsystems.zigbee.console.main/database/ + + # Gradle .gradle build/ diff --git a/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/database/ZclAttributeDao.java b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/database/ZclAttributeDao.java new file mode 100644 index 0000000000..917f532508 --- /dev/null +++ b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/database/ZclAttributeDao.java @@ -0,0 +1,306 @@ +/** + * Copyright (c) 2016-2019 by the respective copyright holders. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package com.zsmartsystems.zigbee.database; + +import java.util.Calendar; + +import com.zsmartsystems.zigbee.zcl.ZclAttribute; +import com.zsmartsystems.zigbee.zcl.protocol.ZclDataType; + +/** + * This class provides a clean class to hold a data object for serialisation of a {@link ZclAttribute} + * + * @author Chris Jackson + * + */ +public class ZclAttributeDao { + /** + * The attribute identifier field is 16-bits in length and shall contain the + * identifier of the attribute that the reporting configuration details + * apply to. + */ + private int id; + + /** + * Stores the name of this attribute; + */ + private String name; + + /** + * Defines the ZigBee data type. + */ + private ZclDataType dataType; + + /** + * Defines if this attribute is mandatory to be implemented + */ + private boolean mandatory; + + /** + * Defines if the attribute is implemented by the device + */ + private boolean implemented; + + /** + * True if this attribute is readable + */ + private boolean readable; + + /** + * True if this attribute is writable + */ + private boolean writable; + + /** + * True if this attribute is reportable + */ + private boolean reportable; + + /** + * The minimum reporting interval field is 16-bits in length and shall + * contain the minimum interval, in seconds, between issuing reports for the + * attribute specified in the attribute identifier field. If the minimum + * reporting interval has not been configured, this field shall contain the + * value 0xffff. + */ + private int minimumReportingPeriod; + + /** + * The maximum reporting interval field is 16-bits in length and shall + * contain the maximum interval, in seconds, between issuing reports for the + * attribute specified in the attribute identifier field. If the maximum + * reporting interval has not been configured, this field shall contain the + * value 0xffff. + */ + private int maximumReportingPeriod; + + /** + * The reportable change field shall contain the minimum change to the + * attribute that will result in a report being issued. For attributes with + * 'analog' data type the field has the same data type as the attribute. If + * the reportable change has not been configured, this field shall contain + * the invalid value for the relevant data type + */ + private Object reportingChange; + + /** + * The timeout period field is 16-bits in length and shall contain the + * maximum expected time, in seconds, between received reports for the + * attribute specified in the attribute identifier field. If the timeout + * period has not been configured, this field shall contain the value + * 0xffff. + */ + private int reportingTimeout; + + /** + * Records the last time a report was received + */ + private Calendar lastReportTime; + + /** + * Records the last value received + */ + private Object lastValue; + + /** + * @return the id + */ + public int getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the dataType + */ + public ZclDataType getDataType() { + return dataType; + } + + /** + * @param dataType the dataType to set + */ + public void setDataType(ZclDataType dataType) { + this.dataType = dataType; + } + + /** + * @return the mandatory + */ + public boolean isMandatory() { + return mandatory; + } + + /** + * @param mandatory the mandatory to set + */ + public void setMandatory(boolean mandatory) { + this.mandatory = mandatory; + } + + /** + * @return the implemented + */ + public boolean isImplemented() { + return implemented; + } + + /** + * @param implemented the implemented to set + */ + public void setImplemented(boolean implemented) { + this.implemented = implemented; + } + + /** + * @return the readable + */ + public boolean isReadable() { + return readable; + } + + /** + * @param readable the readable to set + */ + public void setReadable(boolean readable) { + this.readable = readable; + } + + /** + * @return the writable flag + */ + public boolean isWritable() { + return writable; + } + + /** + * @param writable the writable to set + */ + public void setWritable(boolean writable) { + this.writable = writable; + } + + /** + * @return the reportable + */ + public boolean isReportable() { + return reportable; + } + + /** + * @param reportable the reportable to set + */ + public void setReportable(boolean reportable) { + this.reportable = reportable; + } + + /** + * @return the minimumReportingPeriod + */ + public int getMinimumReportingPeriod() { + return minimumReportingPeriod; + } + + /** + * @param minimumReportingPeriod the minimumReportingPeriod to set + */ + public void setMinimumReportingPeriod(int minimumReportingPeriod) { + this.minimumReportingPeriod = minimumReportingPeriod; + } + + /** + * @return the maximumReportingPeriod + */ + public int getMaximumReportingPeriod() { + return maximumReportingPeriod; + } + + /** + * @param maximumReportingPeriod the maximumReportingPeriod to set + */ + public void setMaximumReportingPeriod(int maximumReportingPeriod) { + this.maximumReportingPeriod = maximumReportingPeriod; + } + + /** + * @return the reportingChange + */ + public Object getReportingChange() { + return reportingChange; + } + + /** + * @param reportingChange the reportingChange to set + */ + public void setReportingChange(Object reportingChange) { + this.reportingChange = reportingChange; + } + + /** + * @return the reportingTimeout + */ + public int getReportingTimeout() { + return reportingTimeout; + } + + /** + * @param reportingTimeout the reportingTimeout to set + */ + public void setReportingTimeout(int reportingTimeout) { + this.reportingTimeout = reportingTimeout; + } + + /** + * @return the lastReportTime + */ + public Calendar getLastReportTime() { + return lastReportTime; + } + + /** + * @param lastReportTime the lastReportTime to set + */ + public void setLastReportTime(Calendar lastReportTime) { + this.lastReportTime = lastReportTime; + } + + /** + * @return the lastValue + */ + public Object getLastValue() { + return lastValue; + } + + /** + * @param lastValue the lastValue to set + */ + public void setLastValue(Object lastValue) { + this.lastValue = lastValue; + } + +} diff --git a/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/database/ZclClusterDao.java b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/database/ZclClusterDao.java index df5a7fca5f..13182ed7ff 100644 --- a/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/database/ZclClusterDao.java +++ b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/database/ZclClusterDao.java @@ -12,7 +12,6 @@ import java.util.Set; import com.zsmartsystems.zigbee.ZigBeeEndpoint; -import com.zsmartsystems.zigbee.zcl.ZclAttribute; /** * This class provides a clean class to hold a data object for serialisation of a {@link ZigBeeEndpoint} @@ -27,7 +26,7 @@ public class ZclClusterDao { private boolean isClient; - private Map attributes; + private Map attributes; private Set supportedCommandsReceived; @@ -43,8 +42,8 @@ public void setLabel(String label) { this.label = label; } - public void setAttributes(Map attributes) { - this.attributes = new HashMap(attributes); + public void setAttributes(Map attributes) { + this.attributes = new HashMap<>(attributes); } public void setSupportedCommandsReceived(Set supportedCommandsReceived) { @@ -85,7 +84,7 @@ public Set getSupportedAttributes() { return supportedAttributes; } - public Map getAttributes() { + public Map getAttributes() { return attributes; } diff --git a/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclAttribute.java b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclAttribute.java index fe00b3de47..2d5b26559f 100644 --- a/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclAttribute.java +++ b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclAttribute.java @@ -12,6 +12,7 @@ import java.util.concurrent.Future; import com.zsmartsystems.zigbee.CommandResult; +import com.zsmartsystems.zigbee.database.ZclAttributeDao; import com.zsmartsystems.zigbee.zcl.protocol.ZclClusterType; import com.zsmartsystems.zigbee.zcl.protocol.ZclDataType; @@ -25,29 +26,29 @@ public class ZclAttribute { /** * */ - private final ZclCluster cluster; + private ZclCluster cluster; /** * The attribute identifier field is 16-bits in length and shall contain the * identifier of the attribute that the reporting configuration details * apply to. */ - private final int id; + private int id; /** * Stores the name of this attribute; */ - private final String name; + private String name; /** * Defines the ZigBee data type. */ - private final ZclDataType dataType; + private ZclDataType dataType; /** * Defines if this attribute is mandatory to be implemented */ - private final boolean mandatory; + private boolean mandatory; /** * Defines if the attribute is implemented by the device @@ -60,9 +61,9 @@ public class ZclAttribute { private boolean readable; /** - * True if this attribute is writeable + * True if this attribute is writable */ - private boolean writeable; + private boolean writable; /** * True if this attribute is reportable @@ -115,6 +116,12 @@ public class ZclAttribute { */ private Object lastValue; + /** + * Default constructor + */ + public ZclAttribute() { + } + /** * Constructor used to set the static information * @@ -123,18 +130,18 @@ public class ZclAttribute { * @param dataType the {@link ZclDataType} for this attribute * @param mandatory true if this is defined as mandatory in the ZCL specification * @param readable true if this is defined as readable in the ZCL specification - * @param writeable true if this is defined as writable in the ZCL specification + * @param writable true if this is defined as writable in the ZCL specification * @param reportable true if this is defined as reportable in the ZCL specification */ public ZclAttribute(final ZclCluster cluster, final int id, final String name, final ZclDataType dataType, - final boolean mandatory, final boolean readable, final boolean writeable, final boolean reportable) { + final boolean mandatory, final boolean readable, final boolean writable, final boolean reportable) { this.cluster = cluster; this.id = id; this.name = name; this.dataType = dataType; this.mandatory = mandatory; this.readable = readable; - this.writeable = writeable; + this.writable = writable; this.reportable = reportable; } @@ -213,7 +220,7 @@ public boolean isReadable() { * @return true if the attribute is writable */ public boolean isWritable() { - return writeable; + return writable; } /** @@ -430,4 +437,55 @@ public String toString() { return builder.toString(); } + + /** + * Sets the state of the attribute from a {@link ZclAttributeDao} which has been restored from a persisted state. + * + * @param dao the {@link ZclAttributeDao} to restore + */ + public void setDao(ZclCluster cluster, ZclAttributeDao dao) { + this.cluster = cluster; + id = dao.getId(); + name = dao.getName(); + dataType = dao.getDataType(); + mandatory = dao.isMandatory(); + implemented = dao.isImplemented(); + writable = dao.isWritable(); + readable = dao.isReadable(); + reportable = dao.isReportable(); + lastValue = dao.getLastValue(); + lastReportTime = dao.getLastReportTime(); + minimumReportingPeriod = dao.getMinimumReportingPeriod(); + maximumReportingPeriod = dao.getMaximumReportingPeriod(); + reportingChange = dao.getReportingChange(); + reportingTimeout = dao.getReportingTimeout(); + } + + /** + * Returns a Data Acquisition Object for this attribute. This is a clean class recording the state of the primary + * fields of the attribute for persistence purposes. + * + * @return the {@link ZclAttributeDao} from this {@link ZclAttribute} + */ + public ZclAttributeDao getDao() { + ZclAttributeDao dao = new ZclAttributeDao(); + + dao.setId(id); + dao.setDataType(dataType); + dao.setName(name); + dao.setMandatory(mandatory); + dao.setImplemented(implemented); + dao.setMinimumReportingPeriod(minimumReportingPeriod); + dao.setMaximumReportingPeriod(maximumReportingPeriod); + dao.setReadable(readable); + dao.setWritable(writable); + dao.setReportable(reportable); + dao.setReportingChange(reportingChange); + dao.setReportingTimeout(reportingTimeout); + dao.setLastValue(lastValue); + dao.setLastReportTime(lastReportTime); + + return dao; + } + } diff --git a/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclCluster.java b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclCluster.java index 6afe61543a..2407f811fe 100644 --- a/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclCluster.java +++ b/com.zsmartsystems.zigbee/src/main/java/com/zsmartsystems/zigbee/zcl/ZclCluster.java @@ -30,6 +30,7 @@ import com.zsmartsystems.zigbee.IeeeAddress; import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.ZigBeeEndpointAddress; +import com.zsmartsystems.zigbee.database.ZclAttributeDao; import com.zsmartsystems.zigbee.database.ZclClusterDao; import com.zsmartsystems.zigbee.internal.NotificationService; import com.zsmartsystems.zigbee.zcl.clusters.general.ConfigureReportingCommand; @@ -1038,12 +1039,18 @@ public ZclClusterDao getDao() { } dao.setSupportedCommandsGenerated(Collections.unmodifiableSet(new TreeSet<>(supportedCommandsGenerated))); dao.setSupportedCommandsReceived(Collections.unmodifiableSet(new TreeSet<>(supportedCommandsReceived))); + Collection daoZclAttributes; if (isClient) { - dao.setAttributes(clientAttributes); + daoZclAttributes = clientAttributes.values(); } else { - dao.setAttributes(serverAttributes); + daoZclAttributes = serverAttributes.values(); } + Map daoAttributes = new HashMap<>(); + for (ZclAttribute attribute : daoZclAttributes) { + daoAttributes.put(attribute.getId(), attribute.getDao()); + } + dao.setAttributes(daoAttributes); return dao; } @@ -1061,10 +1068,18 @@ public void setDao(ZclClusterDao dao) { } supportedCommandsGenerated.addAll(dao.getSupportedCommandsGenerated()); supportedCommandsReceived.addAll(dao.getSupportedCommandsReceived()); + + Map daoZclAttributes = new HashMap<>(); + for (ZclAttributeDao daoAttribute : dao.getAttributes().values()) { + ZclAttribute attribute = new ZclAttribute(); + attribute.setDao(this, daoAttribute); + daoZclAttributes.put(daoAttribute.getId(), attribute); + } + if (isClient) { - clientAttributes = dao.getAttributes(); + clientAttributes = daoZclAttributes; } else { - serverAttributes = dao.getAttributes(); + serverAttributes = daoZclAttributes; } } diff --git a/com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/zcl/ZclAttributeTest.java b/com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/zcl/ZclAttributeTest.java index a3553ddf88..b6564d41b3 100644 --- a/com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/zcl/ZclAttributeTest.java +++ b/com.zsmartsystems.zigbee/src/test/java/com/zsmartsystems/zigbee/zcl/ZclAttributeTest.java @@ -16,6 +16,7 @@ import org.junit.Test; import org.mockito.Mockito; +import com.zsmartsystems.zigbee.database.ZclAttributeDao; import com.zsmartsystems.zigbee.zcl.clusters.ZclOnOffCluster; import com.zsmartsystems.zigbee.zcl.protocol.ZclClusterType; import com.zsmartsystems.zigbee.zcl.protocol.ZclDataType; @@ -83,6 +84,38 @@ public void setReporting() { attribute.setReporting(1, 2, 3); Mockito.verify(cluster, Mockito.times(1)).setReporting(123, 1, 2, 3); + } + @Test + public void dao() { + ZclCluster cluster = Mockito.mock(ZclCluster.class); + ZclAttribute attribute = new ZclAttribute(cluster, 123, "Test Name", ZclDataType.UNSIGNED_8_BIT_INTEGER, true, + false, true, false); + + attribute.updateValue(Integer.valueOf(12345)); + + ZclAttributeDao dao = attribute.getDao(); + assertEquals(123, dao.getId()); + assertEquals("Test Name", dao.getName()); + assertEquals(ZclDataType.UNSIGNED_8_BIT_INTEGER, dao.getDataType()); + assertTrue(dao.isMandatory()); + assertFalse(dao.isImplemented()); + assertTrue(dao.isWritable()); + assertFalse(dao.isReadable()); + assertFalse(dao.isReportable()); + assertEquals(12345, dao.getLastValue()); + + ZclAttribute daoAttribute = new ZclAttribute(); + daoAttribute.setDao(cluster, dao); + + assertEquals(123, daoAttribute.getId()); + assertEquals("Test Name", daoAttribute.getName()); + assertEquals(ZclDataType.UNSIGNED_8_BIT_INTEGER, daoAttribute.getDataType()); + assertTrue(daoAttribute.isMandatory()); + assertFalse(daoAttribute.isImplemented()); + assertTrue(daoAttribute.isWritable()); + assertFalse(daoAttribute.isReadable()); + assertFalse(daoAttribute.isReportable()); + assertEquals(12345, daoAttribute.getLastValue()); } }