Renamed some DeviceData classes, added additional data classes also and better handling in zigbee

This commit is contained in:
Ziver Koc 2021-10-02 19:42:23 +02:00
parent dc200294be
commit 3edea58f8c
18 changed files with 275 additions and 45 deletions

View file

@ -5,4 +5,10 @@ package se.hal.intf;
*/
public interface HalEventConfig extends HalDeviceConfig {
/**
* @return true if this event device is only a reporting data and do not accept writing/changing the data from Hal.
*/
default boolean isReadOnly() {
return false;
}
}

View file

@ -47,9 +47,9 @@ public class EventOverviewWebPage extends HalWebPage {
// change event data
OnOffEventData eventData = new OnOffEventData();
if (request.containsKey("enabled") && "on".equals(request.get("enabled")))
eventData.turnOn();
eventData.setOn();
else
eventData.turnOff();
eventData.setOff();
logger.info("Modifying Event(" + id + ") state: " + eventData.toString());
Event event = Event.getEvent(db, id);

View file

@ -2,13 +2,14 @@ package se.hal.struct.devicedata;
import se.hal.intf.HalSensorData;
public class LightSensorData extends HalSensorData {
public class IlluminanceSensorData extends HalSensorData {
private double lux;
public LightSensorData(){}
public LightSensorData(double lux, long timestamp){
public IlluminanceSensorData(){}
public IlluminanceSensorData(double lux, long timestamp){
this.lux = lux;
this.setTimestamp(timestamp);
}
@ -16,7 +17,7 @@ public class LightSensorData extends HalSensorData {
@Override
public String toString(){
return lux+" lux";
return lux + " lux";
}
// ----------------------------------------
@ -32,10 +33,10 @@ public class LightSensorData extends HalSensorData {
}
/**
* @param lux set the light intensity in lux
* @param data set the light intensity in lux
*/
@Override
public void setData(double lux) {
this.lux = lux;
public void setData(double data) {
this.lux = data;
}
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2015 Ziver
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package se.hal.struct.devicedata;
import se.hal.intf.HalEventData;
public class OccupancyEventData extends HalEventData {
private boolean isOccupied;
public OccupancyEventData() { }
public OccupancyEventData(boolean isOccupied, long timestamp) {
this.isOccupied = isOccupied;
this.setTimestamp(timestamp);
}
public void setOccupied(){
this.isOccupied = true;
}
public void setOccupied(boolean isOccupied){
this.isOccupied = isOccupied;
}
public void setUnoccupied(){
this.isOccupied = false;
}
public void toggle(){
isOccupied = !isOccupied;
}
public boolean isOccupied(){
return isOccupied;
}
@Override
public String toString(){
return isOccupied ? "Occupied" : "Unoccupied";
}
// ----------------------------------------
// Storage methods
// ----------------------------------------
@Override
public double getData() {
return (isOccupied ? 1.0 : 0.0);
}
@Override
public void setData(double data) {
this.isOccupied = data > 0;
}
}

View file

@ -37,10 +37,10 @@ public class OnOffEventData extends HalEventData {
}
public void turnOn(){
public void setOn(){
isOn = true;
}
public void turnOff(){
public void setOff(){
isOn = false;
}
public void toggle(){
@ -66,7 +66,7 @@ public class OnOffEventData extends HalEventData {
}
@Override
public void setData(double enabled) {
this.isOn = enabled > 0;
public void setData(double data) {
this.isOn = data > 0;
}
}

View file

@ -36,10 +36,10 @@ public class OpenClosedEventData extends HalEventData {
this.setTimestamp(timestamp);
}
public void open(){
public void setOpen(){
isOpen = true;
}
public void close(){
public void setClose(){
isOpen = false;
}
public void toggle(){
@ -65,7 +65,7 @@ public class OpenClosedEventData extends HalEventData {
}
@Override
public void setData(double enabled) {
this.isOpen = enabled > 0;
public void setData(double data) {
this.isOpen = data > 0;
}
}

View file

@ -32,7 +32,6 @@ import se.hal.intf.HalDeviceConfig;
import se.hal.intf.HalDeviceData;
import se.hal.struct.Event;
import se.hal.struct.devicedata.OnOffEventData;
import se.hal.struct.devicedata.TemperatureSensorData;
import java.util.HashMap;
@ -71,9 +70,9 @@ public class OnOffTrait extends DeviceTrait {
if ("action.devices.commands.OnOff".equals(execution.command)) {
OnOffEventData eventData = new OnOffEventData();
if ((boolean) execution.getParams().get("on"))
eventData.turnOn();
eventData.setOn();
else
eventData.turnOff();
eventData.setOff();
EventControllerManager.getInstance().send((Event) device, eventData);
}

View file

@ -7,7 +7,7 @@ import se.hal.plugin.tellstick.TellstickDevice;
import se.hal.plugin.tellstick.TellstickSerialComm;
import se.hal.plugin.tellstick.protocol.Oregon0x1A2DProtocol;
import se.hal.struct.devicedata.HumiditySensorData;
import se.hal.struct.devicedata.LightSensorData;
import se.hal.struct.devicedata.IlluminanceSensorData;
import se.hal.struct.devicedata.PowerConsumptionSensorData;
import se.hal.struct.devicedata.TemperatureSensorData;
import zutil.log.LogUtil;
@ -78,7 +78,7 @@ public class Oregon0x1A2D implements TellstickDevice, HalSensorConfig {
case HUMIDITY:
return HumiditySensorData.class;
case LIGHT:
return LightSensorData.class;
return IlluminanceSensorData.class;
case POWER:
return PowerConsumptionSensorData.class;
case TEMPERATURE:

View file

@ -6,7 +6,7 @@ import se.hal.plugin.tellstick.TellstickSerialComm;
import se.hal.plugin.tellstick.device.Oregon0x1A2D;
import se.hal.plugin.tellstick.device.Oregon0x1A2D.OregonSensorType;
import se.hal.struct.devicedata.HumiditySensorData;
import se.hal.struct.devicedata.LightSensorData;
import se.hal.struct.devicedata.IlluminanceSensorData;
import se.hal.struct.devicedata.PowerConsumptionSensorData;
import se.hal.struct.devicedata.TemperatureSensorData;
import zutil.converter.Converter;
@ -90,7 +90,7 @@ public class Oregon0x1A2DProtocol extends TellstickProtocol {
humidityFound = true;
break;
case LIGHT:
dataObj = new LightSensorData(temperature, timestamp);
dataObj = new IlluminanceSensorData(temperature, timestamp);
temperatureFound = true;
break;
case TEMPERATURE:

View file

@ -29,7 +29,7 @@ public class TelstickSerialCommNexaOnOffTest {
System.out.println("Up and Running");
while (true) {
Thread.sleep(2000);
nexaData.turnOn();
nexaData.setOn();
nexaDevice.setUnit(0);
comm.send(nexaDevice, nexaData);
Thread.sleep(2000);
@ -38,7 +38,7 @@ public class TelstickSerialCommNexaOnOffTest {
Thread.sleep(2000);
nexaData.turnOff();
nexaData.setOff();
nexaDevice.setUnit(0);
comm.send(nexaDevice, nexaData);
Thread.sleep(2000);

View file

@ -36,7 +36,9 @@
<!-- NODE -->
<div class="panel-heading">
<a href="#a" data-toggle="collapse" data-target="#node-{{.getIeeeAddress()}}">Node: {{.getIeeeAddress()}}</a>
<a href="#a" data-toggle="collapse" data-target="#node-{{.getIeeeAddress()}}">
Node: {{.getIeeeAddress()}}
</a>
</div>
<div id="node-{{.getIeeeAddress()}}" class="panel-body collapse">
<div class="col-md-6">
@ -100,7 +102,9 @@
{{#.getEndpoints()}}
<div class="panel panel-default drop-shadow">
<div class="panel-heading">
<a href="#a" data-toggle="collapse" data-target="#node-{{.getIeeeAddress()}}-endpoint-{{.getDeviceId()}}">Endpoint: {{.getDeviceId()}}</a>
<a href="#a" data-toggle="collapse" data-target="#node-{{.getIeeeAddress()}}-endpoint-{{.getDeviceId()}}">
Endpoint: {{.getDeviceId()}}
</a>
</div>
<div id="node-{{.getIeeeAddress()}}-endpoint-{{.getDeviceId()}}" class="panel-body collapse">
@ -109,7 +113,9 @@
{{#.inputClusters.values()}}
<div class="panel panel-default drop-shadow">
<div class="panel-heading">
<a href="#a" data-toggle="collapse" data-target="#node-{{.getZigBeeAddress().getAddress()}}-endpoint-{{.getZigBeeAddress().getEndpoint()}}-in-cluster-{{.getClusterId()}}">Cluster: {{.getClusterId()}}</a>
<a href="#a" data-toggle="collapse" data-target="#node-{{.getZigBeeAddress().getAddress()}}-endpoint-{{.getZigBeeAddress().getEndpoint()}}-in-cluster-{{.getClusterId()}}">
Cluster: {{.CLUSTER_NAME}} ({{.getClusterId()}})
</a>
</div>
<div id="node-{{.getZigBeeAddress().getAddress()}}-endpoint-{{.getZigBeeAddress().getEndpoint()}}-in-cluster-{{.getClusterId()}}" class="panel-body collapse">
<table class="table table-hover table-condensed">
@ -137,7 +143,9 @@
{{#.outputClusters.values()}}
<div class="panel panel-default drop-shadow">
<div class="panel-heading">
<a data-toggle="collapse" data-target="#node-{{.getZigBeeAddress().getAddress()}}-endpoint-{{.getZigBeeAddress().getEndpoint()}}-out-cluster-{{.getClusterId()}}">Cluster: {{.getClusterId()}}</a>
<a data-toggle="collapse" data-target="#node-{{.getZigBeeAddress().getAddress()}}-endpoint-{{.getZigBeeAddress().getEndpoint()}}-out-cluster-{{.getClusterId()}}">
Cluster: {{.CLUSTER_NAME}} ({{.getClusterId()}})
</a>
</div>
<div id="node-{{.getZigBeeAddress().getAddress()}}-endpoint-{{.getZigBeeAddress().getEndpoint()}}-out-cluster-{{.getClusterId()}}" class="panel-body collapse">

View file

@ -20,10 +20,12 @@ import com.zsmartsystems.zigbee.zcl.ZclAttributeListener;
import com.zsmartsystems.zigbee.zcl.ZclCluster;
import com.zsmartsystems.zigbee.zcl.clusters.*;
import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor;
import se.hal.HalContext;
import se.hal.intf.*;
import se.hal.plugin.zigbee.db.ZigBeeHalDataStore;
import se.hal.plugin.zigbee.device.*;
import zutil.Timer;
import zutil.log.LogUtil;
@ -291,7 +293,7 @@ public class ZigbeeController implements HalSensorController,
for (int inputClusterId : endpoint.getInputClusterIds()) {
ZclCluster cluster = endpoint.getInputCluster(inputClusterId);
ZigbeeHalDeviceConfig config = createDeviceConfig(inputClusterId);
ZigbeeHalDeviceConfig config = ZigbeeHalDeviceFactory.getDeviceConfig(inputClusterId);
// Read basic attributes
if (cluster instanceof ZclBasicCluster) {
@ -338,18 +340,6 @@ public class ZigbeeController implements HalSensorController,
}
}
private ZigbeeHalDeviceConfig createDeviceConfig(int clusterId) {
switch (clusterId) {
case ZclRelativeHumidityMeasurementCluster.CLUSTER_ID: return new ZigbeeHumidityConfig();
case ZclOnOffCluster.CLUSTER_ID: return new ZigbeeOnOffConfig();
case ZclPressureMeasurementCluster.CLUSTER_ID: return new ZigbeePressureConfig();
case ZclTemperatureMeasurementCluster.CLUSTER_ID: return new ZigbeeTemperatureConfig();
}
return null;
}
@Override
public void deviceRemoved(ZigBeeEndpoint endpoint) {
logger.fine("[Node: " + endpoint.getIeeeAddress() + ", Endpoint: " + endpoint.getEndpointId() + "]: Endpoint removed: " + endpoint);

View file

@ -0,0 +1,40 @@
package se.hal.plugin.zigbee.device;
import zutil.log.LogUtil;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A factory class for getting new instances of {@link ZigbeeHalDeviceConfig} objects.
*/
public class ZigbeeHalDeviceFactory {
private static final Logger logger = LogUtil.getLogger();
private static final HashMap<Integer, Class<? extends ZigbeeHalDeviceConfig>> clusterDeviceMap = new HashMap<>();
static {
clusterDeviceMap.put(new ZigbeeHumidityConfig().getZigbeeClusterId(), ZigbeeHumidityConfig.class);
clusterDeviceMap.put(new ZigbeeIlluminanceConfig().getZigbeeClusterId(), ZigbeeIlluminanceConfig.class);
clusterDeviceMap.put(new ZigbeeOccupancyConfig().getZigbeeClusterId(), ZigbeeOccupancyConfig.class);
clusterDeviceMap.put(new ZigbeeOnOffConfig().getZigbeeClusterId(), ZigbeeOnOffConfig.class);
clusterDeviceMap.put(new ZigbeePressureConfig().getZigbeeClusterId(), ZigbeePressureConfig.class);
clusterDeviceMap.put(new ZigbeeTemperatureConfig().getZigbeeClusterId(), ZigbeeTemperatureConfig.class);
}
public static ZigbeeHalDeviceConfig getDeviceConfig(int cluster) {
try {
Class<? extends ZigbeeHalDeviceConfig> clazz = clusterDeviceMap.get(cluster);
if (clazz != null) {
return clazz.getDeclaredConstructor().newInstance();
}
} catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
logger.log(Level.SEVERE, "Unable to instantiate ZigbeeHalDeviceConfig: " + clusterDeviceMap.get(cluster), e);
}
return null;
}
}

View file

@ -55,6 +55,8 @@ public abstract class ZigbeeHalEventDeviceConfig extends ZigbeeHalDeviceConfig {
* @param data is the Hal event data value that should be converted.
* @return a new Zigbee command object or null if no equal representation can be created based on the data.
*/
protected abstract ZclCommand getZigbeeCommandObject(HalEventData data);
protected ZclCommand getZigbeeCommandObject(HalEventData data) {
return null;
}
}

View file

@ -0,0 +1,46 @@
package se.hal.plugin.zigbee.device;
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
import com.zsmartsystems.zigbee.zcl.clusters.ZclIlluminanceMeasurementCluster;
import se.hal.intf.HalDeviceData;
import se.hal.intf.HalSensorConfig;
import se.hal.struct.devicedata.IlluminanceSensorData;
/**
* A device configuration for a specific endpoint on a Zigbee device.
*/
public class ZigbeeIlluminanceConfig extends ZigbeeHalDeviceConfig implements HalSensorConfig {
// --------------------------
// Zigbee Methods
// --------------------------
@Override
public HalDeviceData getDeviceData(ZclAttribute zclAttribute) {
if (zclAttribute.getCluster().getId() == getZigbeeClusterId() &&
zclAttribute.getId() == ZclIlluminanceMeasurementCluster.ATTR_MEASUREDVALUE)
return new IlluminanceSensorData(
(int) zclAttribute.getLastValue(),
zclAttribute.getLastReportTime().getTimeInMillis());
return null;
}
@Override
public int getZigbeeClusterId() {
return ZclIlluminanceMeasurementCluster.CLUSTER_ID;
}
// --------------------------
// Hal Methods
// --------------------------
@Override
public AggregationMethod getAggregationMethod() {
return AggregationMethod.AVERAGE;
}
@Override
public Class<? extends HalDeviceData> getDeviceDataClass() {
return IlluminanceSensorData.class;
}
}

View file

@ -0,0 +1,62 @@
package se.hal.plugin.zigbee.device;
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
import com.zsmartsystems.zigbee.zcl.ZclCluster;
import com.zsmartsystems.zigbee.zcl.clusters.ZclOccupancySensingCluster;
import se.hal.intf.HalDeviceData;
import se.hal.intf.HalEventConfig;
import se.hal.struct.devicedata.OccupancyEventData;
import zutil.log.LogUtil;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A device configuration for a specific endpoint on a Zigbee device.
*/
public class ZigbeeOccupancyConfig extends ZigbeeHalEventDeviceConfig implements HalEventConfig {
private static final Logger logger = LogUtil.getLogger();
// --------------------------
// Zigbee Methods
// --------------------------
@Override
public void initialize(ZclCluster cluster) {
if (! (cluster instanceof ZclOccupancySensingCluster))
return;
try {
ZclAttribute attribute = cluster.getAttribute(ZclOccupancySensingCluster.ATTR_OCCUPANCY);
attribute.setReporting(1, 900).get();
attribute.readValue(60);
} catch (Exception e) {
logger.log(Level.WARNING, "Was unable to initialize cluster reporting rate.", e);
}
}
@Override
public HalDeviceData getDeviceData(ZclAttribute zclAttribute) {
if (zclAttribute.getCluster().getId() == getZigbeeClusterId() &&
zclAttribute.getId() == ZclOccupancySensingCluster.ATTR_OCCUPANCY)
return new OccupancyEventData(
(boolean) zclAttribute.getLastValue(),
zclAttribute.getLastReportTime().getTimeInMillis());
return null;
}
@Override
public int getZigbeeClusterId() {
return ZclOccupancySensingCluster.CLUSTER_ID;
}
// --------------------------
// Hal Methods
// --------------------------
@Override
public Class<? extends HalDeviceData> getDeviceDataClass() {
return OccupancyEventData.class;
}
}

View file

@ -20,7 +20,7 @@ public class ZigbeePressureConfig extends ZigbeeHalDeviceConfig implements HalSe
@Override
public HalDeviceData getDeviceData(ZclAttribute zclAttribute) {
if (zclAttribute.getCluster().getId() == getZigbeeClusterId() &&
zclAttribute.getId() == ZclTemperatureMeasurementCluster.ATTR_MAXMEASUREDVALUE)
zclAttribute.getId() == ZclTemperatureMeasurementCluster.ATTR_MEASUREDVALUE)
return new PressureSensorData(
(int) zclAttribute.getLastValue(),
zclAttribute.getLastReportTime().getTimeInMillis());

View file

@ -7,6 +7,8 @@
{"se.hal.intf.HalEventConfig": "se.hal.plugin.zigbee.device.ZigbeeOnOffConfig"},
{"se.hal.intf.HalSensorConfig": "se.hal.plugin.zigbee.device.ZigbeeHumidityConfig"},
{"se.hal.intf.HalSensorConfig": "se.hal.plugin.zigbee.device.ZigbeeIlluminanceConfig"},
{"se.hal.intf.HalEventConfig": "se.hal.plugin.zigbee.device.ZigbeeOccupancyConfig"},
{"se.hal.intf.HalSensorConfig": "se.hal.plugin.zigbee.device.ZigbeePressureConfig"},
{"se.hal.intf.HalSensorConfig": "se.hal.plugin.zigbee.device.ZigbeeTemperatureConfig"},