diff --git a/build.gradle b/build.gradle index 881adf84..c84c2c78 100644 --- a/build.gradle +++ b/build.gradle @@ -18,8 +18,8 @@ subprojects { apply plugin: 'java-library' dependencies { - implementation 'se.koc:zutil:1.0.311' - //implementation 'se.koc:zutil:1.0.0-SNAPSHOT' + //implementation 'se.koc:zutil:1.0.312' + implementation 'se.koc:zutil:1.0.0-SNAPSHOT' testImplementation 'junit:junit:4.12' testImplementation 'org.hamcrest:hamcrest-core:2.2' diff --git a/hal-core/resources/web/event_detail.tmpl b/hal-core/resources/web/event_detail.tmpl index 24d71e02..91451ac5 100644 --- a/hal-core/resources/web/event_detail.tmpl +++ b/hal-core/resources/web/event_detail.tmpl @@ -28,7 +28,7 @@
- +
Last Update Actions - {{#events}} - - {{.getName()}} - {{.getDeviceConfig().getClass().getSimpleName()}} - {{.getDeviceData()}} - {{.getDeviceData().getTimestamp()}} - - - - - -
- -
- - - - {{/events}}
@@ -45,24 +25,70 @@ }); }); + updateDevices(); + // Auto update setInterval(function() { + updateDevices(); + }, 3000); + + function updateDevices() { fetch('/api/event') .then(response => response.json()) .then(data => { var table = document.getElementById('event-device-table'); - for (const row of table.rows) { - var dataItem = data.find(item => item.id == row.dataset.deviceId); + for (const deviceData of data) { + var row = Array.from(table.rows).find(row => row.dataset.deviceId == deviceData.id); - if (dataItem) { - row.cells[2].innerHTML = dataItem.data?.valueStr; - row.cells[3].innerHTML = dataItem.data?.timestamp; - $(row.cells[3]).relTimestamp(); - $(row.cells[4].querySelector('[type="checkbox"]')).bootstrapSwitch('state', dataItem.data?.value === 1, true); + if (!row) { + row = table.insertRow(); + row.insertCell(0); + row.insertCell(1); + row.insertCell(2); + row.insertCell(3); + row.insertCell(4); } + + // Update Cells + + row.dataset.deviceId = deviceData.id + row.cells[0].innerHTML = deviceData.name; + row.cells[1].innerHTML = deviceData.config?.typeConfig; + row.cells[2].innerHTML = deviceData.data?.valueStr; + + row.cells[3].innerHTML = deviceData.data?.timestamp; + $(row.cells[3]).relTimestamp(); + + var actionHtml = ""; + switch (deviceData.config?.typeData) { + case "ColorEventData": + actionHtml = + '' + + ''; + break; + case "LevelEventData": + actionHtml = + '' + + ''; + break; + case "OnOffEventData": + actionHtml = + '' + + ''; + //$(row.cells[4].querySelector('[type="checkbox"]')).bootstrapSwitch('state', deviceData.data?.value === 1, true); + break; + + + } + row.cells[4].innerHTML = '
' + + '' + + '' + + '
' + actionHtml + '
'; + + $(".toggle-switch").bootstrapSwitch({inverse: true, size: "mini"}); } }); - }, 3000); + } \ No newline at end of file diff --git a/hal-core/resources/web/js/hal_alert.js b/hal-core/resources/web/js/hal_alert.js index 4e475ea4..e2e9baa7 100644 --- a/hal-core/resources/web/js/hal_alert.js +++ b/hal-core/resources/web/js/hal_alert.js @@ -58,6 +58,7 @@ function updateAlerts() { .then(data => { data.forEach(alert => { var alertElement = $("#alert-id-" + alert.id); + if (alertElement.length <= 0) { alertElement = $(alertTemplate[alert.level]); $("#" + alertDivId).append(alertElement); diff --git a/hal-core/resources/web/sensor_overview.tmpl b/hal-core/resources/web/sensor_overview.tmpl index 3a7b537c..838d6cca 100644 --- a/hal-core/resources/web/sensor_overview.tmpl +++ b/hal-core/resources/web/sensor_overview.tmpl @@ -41,11 +41,11 @@ var table = document.getElementById('sensor-device-table'); for (const row of table.rows) { - var dataItem = data.find(item => item.id == row.dataset.deviceId); + var deviceData = data.find(item => item.id == row.dataset.deviceId); - if (dataItem) { - row.cells[2].innerHTML = dataItem.data?.valueStr; - row.cells[3].innerHTML = dataItem.data?.timestamp; + if (deviceData) { + row.cells[2].innerHTML = deviceData.data?.valueStr; + row.cells[3].innerHTML = deviceData.data?.timestamp; $(row.cells[3]).relTimestamp(); } diff --git a/hal-core/src/se/hal/page/EventOverviewWebPage.java b/hal-core/src/se/hal/page/EventOverviewWebPage.java index f0889b03..d2c1b702 100644 --- a/hal-core/src/se/hal/page/EventOverviewWebPage.java +++ b/hal-core/src/se/hal/page/EventOverviewWebPage.java @@ -2,8 +2,11 @@ package se.hal.page; import se.hal.EventControllerManager; import se.hal.HalContext; +import se.hal.intf.HalEventData; import se.hal.intf.HalWebPage; import se.hal.struct.Event; +import se.hal.struct.devicedata.ColorEventData; +import se.hal.struct.devicedata.LevelEventData; import se.hal.struct.devicedata.OnOffEventData; import se.hal.util.DeviceNameComparator; import se.hal.util.HistoryDataListSqlResult; @@ -41,24 +44,40 @@ public class EventOverviewWebPage extends HalWebPage { DBConnection db = HalContext.getDB(); - if (request.containsKey("action")) { - int id = (ObjectUtil.isEmpty(request.get("action_id")) ? -1 : Integer.parseInt(request.get("action_id"))); + if ("modify".equals(request.get("action"))) { + int id = (ObjectUtil.isEmpty(request.get("action-id")) ? -1 : Integer.parseInt(request.get("action-id"))); // change event data - OnOffEventData eventData = new OnOffEventData(); - if (request.containsKey("enabled") && "on".equals(request.get("enabled"))) - eventData.setOn(); - else - eventData.setOff(); + HalEventData eventData = null; - logger.info("Modifying Event(" + id + ") state: " + eventData.toString()); - Event event = Event.getEvent(db, id); - EventControllerManager.getInstance().send(event, eventData); + switch (request.get("type")) { + case "level": + eventData = new LevelEventData(Integer.parseInt(request.get("data")) / 100.0, 0); + break; + + case "color": + eventData = new ColorEventData(request.get("data"), 0); + break; + + case "on-off": + eventData = new OnOffEventData("on".equals(request.get("data")), 0); + break; + } + + if (eventData != null) { + logger.info("Modifying Event(" + id + ") state: " + eventData.toString()); + Event event = Event.getEvent(db, id); + EventControllerManager.getInstance().send(event, eventData); + } else { + logger.warning("Unable to process event change request, data type most likely not supported: " + request.get("type")); + } } int id = (ObjectUtil.isEmpty(request.get("id")) ? -1 : Integer.parseInt(request.get("id"))); - // Save new input + // -------------------------------------- + // Detailed page + // -------------------------------------- if (id >= 0) { Event event = Event.getEvent(db, id); @@ -74,6 +93,9 @@ public class EventOverviewWebPage extends HalWebPage { tmpl.set("history", history); return tmpl; } + // -------------------------------------- + // Overview page + // -------------------------------------- else { List events = Event.getLocalEvents(db); Collections.sort(events, DeviceNameComparator.getInstance()); diff --git a/hal-core/src/se/hal/struct/devicedata/ColorEventData.java b/hal-core/src/se/hal/struct/devicedata/ColorEventData.java new file mode 100644 index 00000000..3bebcb44 --- /dev/null +++ b/hal-core/src/se/hal/struct/devicedata/ColorEventData.java @@ -0,0 +1,131 @@ +/* + * 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; +import zutil.ColorUtil; +import zutil.converter.Converter; + +import java.awt.*; +import java.awt.color.ColorSpace; + +/** + * Represents a color based event. + */ +public class ColorEventData extends HalEventData { + private static final ColorSpace cieXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + + private int red; + private int green; + private int blue; + + + public ColorEventData() { } + /** + * Create object based on sRGB. + */ + public ColorEventData(String hex, long timestamp) { + int[] rgb = ColorUtil.getRgbFromHexString(hex); + this.red = rgb[0]; + this.green = rgb[1]; + this.blue = rgb[2]; + this.setTimestamp(timestamp); + } + /** + * Create object based on sRGB. + */ + public ColorEventData(int red, int green, int blue, long timestamp) { + this.red = red; + this.green = green; + this.blue = blue; + this.setTimestamp(timestamp); + } + /** + * Create object based on CIE XYZ. + */ + public static ColorEventData createFromCieXYZ(float x, float y, float z, long timestamp) { + float[] rgb = cieXYZ.toRGB(new float[]{x, y, z}); + return new ColorEventData((int) rgb[0], (int) rgb[0], (int) rgb[0], timestamp); + } + /** + * Create object based on HLS. + */ + public static ColorEventData createFromHLS(float h, float l, float s, long timestamp) { + return null; + } + + + public int getRed() { + return red; + } + public int getGreen() { + return green; + } + public int getBlue() { + return blue; + } + + public double getHue() { + return ColorUtil.getHue(red, green, blue); + } + public double getSaturation() { + return ColorUtil.getSaturation(red, green, blue); + } + public double getLightness() { + return ColorUtil.getLightness(red, green, blue); + } + + public float[] getCieXYZ() { + return cieXYZ.fromRGB(new float[]{red, green, blue}); + } + + public String getHex() { + return ColorUtil.getHexString(red, green, blue); + } + + @Override + public String toString(){ + return "Red: " + red + ", Green: " + green + ", Blue: " + blue; + } + + // ---------------------------------------- + // Storage methods + // ---------------------------------------- + + @Override + public double getData() { + int rgb = 0; + rgb |= 0xFF0000 & (red << 16); + rgb |= 0x00FF00 & (green << 8); + rgb |= 0x0000FF & (blue); + return rgb; + } + + @Override + public void setData(double data) { + int rgb = (int) data; + red = 0xFF & (rgb >> 16); + green = 0xFF & (rgb >> 8); + blue = 0xFF & (rgb); + } +} diff --git a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttDeviceData.java b/hal-core/src/se/hal/struct/devicedata/LevelEventData.java similarity index 65% rename from plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttDeviceData.java rename to hal-core/src/se/hal/struct/devicedata/LevelEventData.java index 87ab2688..ab1cf79a 100644 --- a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttDeviceData.java +++ b/hal-core/src/se/hal/struct/devicedata/LevelEventData.java @@ -1,7 +1,5 @@ /* - * The MIT License (MIT) - * - * Copyright (c) 2020 Ziver Koc + * 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 @@ -22,38 +20,40 @@ * THE SOFTWARE. */ -package se.hal.plugin.mqtt.device; +package se.hal.struct.devicedata; import se.hal.intf.HalEventData; -import zutil.StringUtil; -import zutil.log.LogUtil; -import java.util.logging.Logger; +/** + * Represents a percentage based level event. + */ +public class LevelEventData extends HalEventData { -public class HalMqttDeviceData extends HalEventData { - private static final Logger logger = LogUtil.getLogger(); - - private double data; + private double percent; - public HalMqttDeviceData(byte[] byteData) { - String str = new String(byteData); - - if (StringUtil.isDecimalNumber(str)) { - data = Double.parseDouble(str); - } else { - logger.warning("Received non numeric MQTT data."); - } + public LevelEventData() { } + public LevelEventData(double percent, long timestamp) { + setData(percent); + this.setTimestamp(timestamp); } + @Override + public String toString(){ + return Math.floor(percent * 100) + "%"; + } + + // ---------------------------------------- + // Storage methods + // ---------------------------------------- @Override public double getData() { - return data; + return percent; } @Override public void setData(double data) { - this.data = data; + this.percent = data; } } diff --git a/hal-core/src/se/hal/struct/devicedata/OnOffEventData.java b/hal-core/src/se/hal/struct/devicedata/OnOffEventData.java index 4fe909d1..fc503eab 100644 --- a/hal-core/src/se/hal/struct/devicedata/OnOffEventData.java +++ b/hal-core/src/se/hal/struct/devicedata/OnOffEventData.java @@ -24,7 +24,9 @@ package se.hal.struct.devicedata; import se.hal.intf.HalEventData; - +/** + * Represents a 'ON' or 'OFF' state based event. + */ public class OnOffEventData extends HalEventData { private boolean isOn; diff --git a/hal-core/src/se/hal/struct/devicedata/OpenClosedEventData.java b/hal-core/src/se/hal/struct/devicedata/OpenClosedEventData.java index 45de33d7..4324f745 100644 --- a/hal-core/src/se/hal/struct/devicedata/OpenClosedEventData.java +++ b/hal-core/src/se/hal/struct/devicedata/OpenClosedEventData.java @@ -25,6 +25,9 @@ package se.hal.struct.devicedata; import se.hal.intf.HalEventData; +/** + * Represents an 'Opened' or 'Closed' state based event. + */ public class OpenClosedEventData extends HalEventData { private boolean isOpen; diff --git a/hal-core/test/se/hal/struct/devicedata/ColorEventDataTest.java b/hal-core/test/se/hal/struct/devicedata/ColorEventDataTest.java new file mode 100644 index 00000000..a42afd56 --- /dev/null +++ b/hal-core/test/se/hal/struct/devicedata/ColorEventDataTest.java @@ -0,0 +1,46 @@ +package se.hal.struct.devicedata; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class ColorEventDataTest { + + @Test + public void getData() { + assertEquals(0.0, new ColorEventData(0, 0, 0, 0).getData(), 0); + assertEquals(6553600.0, new ColorEventData(100, 0, 0, 0).getData(), 0); + assertEquals(25600.0, new ColorEventData(0, 100, 0, 0).getData(), 0); + assertEquals(100.0, new ColorEventData(0, 0, 100, 0).getData(), 0); + assertEquals(16777215.0, new ColorEventData(255, 255, 255, 0).getData(), 0); + } + + @Test + public void setData() { + ColorEventData colorData = new ColorEventData(); + colorData.setData(0); + assertEquals(0, colorData.getRed()); + assertEquals(0, colorData.getGreen()); + assertEquals(0, colorData.getBlue()); + + colorData.setData(6553600.0); + assertEquals(100, colorData.getRed()); + assertEquals(0, colorData.getGreen()); + assertEquals(0, colorData.getBlue()); + + colorData.setData(25600.0); + assertEquals(0, colorData.getRed()); + assertEquals(100, colorData.getGreen()); + assertEquals(0, colorData.getBlue()); + + colorData.setData(100.0); + assertEquals(0, colorData.getRed()); + assertEquals(0, colorData.getGreen()); + assertEquals(100, colorData.getBlue()); + + colorData.setData(16777215.0); + assertEquals(255, colorData.getRed()); + assertEquals(255, colorData.getGreen()); + assertEquals(255, colorData.getBlue()); + } +} \ No newline at end of file diff --git a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/HalMqttController.java b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/HalMqttController.java index c3c3e365..aa98a2ec 100644 --- a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/HalMqttController.java +++ b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/HalMqttController.java @@ -27,15 +27,14 @@ package se.hal.plugin.mqtt; import se.hal.daemon.HalMulticastDnsDaemon; import se.hal.intf.*; import se.hal.plugin.mqtt.device.HalMqttDeviceConfig; -import se.hal.plugin.mqtt.device.HalMqttDeviceData; import zutil.InetUtil; import zutil.log.LogUtil; -import zutil.net.dns.MulticastDnsServer; import zutil.net.mqtt.MqttBroker; import zutil.net.mqtt.MqttSubscriptionListener; import java.io.IOException; import java.net.InetAddress; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -47,7 +46,7 @@ public class HalMqttController implements HalAutostartController, MqttSubscripti private MqttBroker mqttBroker; - private HashMap topics = new HashMap<>(); + private HashMap> topics = new HashMap<>(); private List deviceListeners = new CopyOnWriteArrayList<>(); // -------------------------- @@ -67,6 +66,7 @@ public class HalMqttController implements HalAutostartController, MqttSubscripti logger.info("Starting up MQTT Server"); mqttBroker = new MqttBroker(); + mqttBroker.addGlobalSubscriber(this); mqttBroker.start(); } catch (IOException e) { @@ -96,14 +96,16 @@ public class HalMqttController implements HalAutostartController, MqttSubscripti @Override public void dataPublished(String topic, byte[] data) { - HalMqttDeviceConfig eventConfig = topics.get(topic); + List devices = topics.get(topic); - if (eventConfig != null && data.length > 0) { - HalMqttDeviceData eventData = new HalMqttDeviceData(data); + if (devices != null && data.length > 0) { + for (HalMqttDeviceConfig deviceConfig : devices) { + HalDeviceData deviceData = deviceConfig.getDeviceData(data); - if (deviceListeners != null) { - for (HalDeviceReportListener deviceListener : deviceListeners) { - deviceListener.reportReceived(eventConfig, eventData); + if (deviceListeners != null) { + for (HalDeviceReportListener deviceListener : deviceListeners) { + deviceListener.reportReceived(deviceConfig, deviceData); + } } } } @@ -121,7 +123,10 @@ public class HalMqttController implements HalAutostartController, MqttSubscripti public void register(HalDeviceConfig deviceConfig) { if (deviceConfig instanceof HalMqttDeviceConfig) { HalMqttDeviceConfig mqttEvent = (HalMqttDeviceConfig) deviceConfig; - topics.put(mqttEvent.getTopic(), mqttEvent); + + if (!topics.containsKey(mqttEvent.getTopic())) + topics.put(mqttEvent.getTopic(), new ArrayList<>()); + topics.get(mqttEvent.getTopic()).add(mqttEvent); } else { throw new IllegalArgumentException( "Device config is not an instance of " + HalMqttDeviceConfig.class + ": " + deviceConfig.getClass()); @@ -132,7 +137,8 @@ public class HalMqttController implements HalAutostartController, MqttSubscripti public void deregister(HalDeviceConfig deviceConfig) { if (deviceConfig instanceof HalMqttDeviceConfig) { HalMqttDeviceConfig mqttEvent = (HalMqttDeviceConfig) deviceConfig; - topics.remove(mqttEvent.getTopic()); + if (topics.containsKey(mqttEvent.getTopic())) + topics.get(mqttEvent.getTopic()).remove(deviceConfig); } } @@ -147,7 +153,11 @@ public class HalMqttController implements HalAutostartController, MqttSubscripti @Override public int size() { - return topics.size(); + int size = 0; + for (List devices : topics.values()) { + size += devices.size(); + } + return size; } @Override diff --git a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttDeviceConfig.java b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttDeviceConfig.java index 6baf96a4..ca5c99cb 100644 --- a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttDeviceConfig.java +++ b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttDeviceConfig.java @@ -48,23 +48,34 @@ package se.hal.plugin.mqtt.device; -import se.hal.intf.HalEventConfig; +import se.hal.intf.HalDeviceData; import se.hal.intf.HalEventController; import se.hal.intf.HalEventData; +import se.hal.intf.HalSensorConfig; import se.hal.plugin.mqtt.HalMqttController; +import zutil.ui.conf.Configurator; -public class HalMqttDeviceConfig implements HalEventConfig { - private final String topic; - - - public HalMqttDeviceConfig(String topic) { - this.topic = topic; - } +public abstract class HalMqttDeviceConfig implements HalSensorConfig { + @Configurator.Configurable(value = "MQTT Topic") + private String topic; + @Configurator.Configurable(value = "JSON Path", description = "If the value of the topic is a JSON then this parameter can be used to specify the path to the e.g. temperature value." + + "
THe parameter uses the JSON-Path syntax where it always starts with $ and object fields can be accessed by . and a array element by [index]") + private String jsonPath; public String getTopic() { return topic; } + public void setTopic(String topic) { + this.topic = topic; + } + + public String getJsonPath() { + return jsonPath; + } + public void setJsonPath(String jsonPath) { + this.jsonPath = jsonPath; + } // -------------------------- // Hal Methods @@ -75,15 +86,25 @@ public class HalMqttDeviceConfig implements HalEventConfig { return HalMqttController.class; } - @Override - public Class getDeviceDataClass() { - return HalMqttDeviceData.class; - } + /** + * @param data the data published to the MQTT topic. + * @return a new data object instance containing the device data based on the input data. + */ + public abstract HalDeviceData getDeviceData(byte[] data); + + // -------------------------- + // Java Methods + // -------------------------- @Override public boolean equals(Object obj) { if (obj instanceof HalMqttDeviceConfig) - return topic.equals(((HalMqttDeviceConfig) obj).topic); + return topic.equals(((HalMqttDeviceConfig) obj).topic) && jsonPath.equals(((HalMqttDeviceConfig) obj).jsonPath); return false; } + + @Override + public String toString() { + return "Topic: " + topic + ", JSON Path: " + jsonPath; + } } diff --git a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttParticularMatterDeviceConfig.java b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttParticularMatterDeviceConfig.java new file mode 100644 index 00000000..41917238 --- /dev/null +++ b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/device/HalMqttParticularMatterDeviceConfig.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ziver Koc + * + * 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. + */ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ziver Koc + * + * 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.plugin.mqtt.device; + +import se.hal.intf.HalDeviceData; +import se.hal.intf.HalEventController; +import se.hal.plugin.mqtt.HalMqttController; +import se.hal.struct.devicedata.TemperatureSensorData; +import zutil.ObjectUtil; +import zutil.converter.Converter; +import zutil.parser.DataNode; +import zutil.parser.DataNodePath; +import zutil.parser.json.JSONParser; + +import java.nio.charset.StandardCharsets; + +public class HalMqttParticularMatterDeviceConfig extends HalMqttDeviceConfig { + + // -------------------------- + // Hal Methods + // -------------------------- + + @Override + public Class getDeviceControllerClass() { + return HalMqttController.class; + } + + @Override + public Class getDeviceDataClass() { + return TemperatureSensorData.class; + } + + @Override + public HalDeviceData getDeviceData(byte[] data) { + if (!ObjectUtil.isEmpty(getJsonPath())) { + String dataStr = new String(data, StandardCharsets.UTF_8); + DataNode json = JSONParser.read(dataStr); + DataNode deviceDataValue = DataNodePath.search(getJsonPath(), json); + + if (deviceDataValue != null) + return new TemperatureSensorData(deviceDataValue.getDouble(), System.currentTimeMillis()); + else + return null; + } + return new TemperatureSensorData(Converter.toInt(data), System.currentTimeMillis()); + } + + @Override + public AggregationMethod getAggregationMethod() { + return AggregationMethod.AVERAGE; + } +} diff --git a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/plugin.json b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/plugin.json index 5fecee3e..d6f5a1fe 100644 --- a/plugins/hal-mqtt/src/se/hal/plugin/mqtt/plugin.json +++ b/plugins/hal-mqtt/src/se/hal/plugin/mqtt/plugin.json @@ -4,6 +4,8 @@ "interfaces": [ {"se.hal.intf.HalAutostartController": "se.hal.plugin.mqtt.HalMqttController"}, + {"se.hal.intf.HalSensorConfig": "se.hal.plugin.mqtt.device.HalMqttParticularMatterDeviceConfig"}, + {"se.hal.intf.HalWebPage": "se.hal.plugin.mqtt.page.MqttOverviewPage"} ] } \ No newline at end of file diff --git a/plugins/hal-zigbee/build.gradle b/plugins/hal-zigbee/build.gradle index 772e0b1e..c72615f0 100644 --- a/plugins/hal-zigbee/build.gradle +++ b/plugins/hal-zigbee/build.gradle @@ -1,5 +1,5 @@ dependencies { - def ZIGBEE_LIB_VERSION = "1.3.8" + def ZIGBEE_LIB_VERSION = "1.4.11" implementation project(':hal-core') diff --git a/plugins/hal-zigbee/resources/web/zigbee_network.tmpl b/plugins/hal-zigbee/resources/web/zigbee_network.tmpl index 62e9d553..bfd472d0 100644 --- a/plugins/hal-zigbee/resources/web/zigbee_network.tmpl +++ b/plugins/hal-zigbee/resources/web/zigbee_network.tmpl @@ -35,10 +35,19 @@
-
- - Node: {{.getIeeeAddress()}} - +
@@ -122,6 +131,7 @@ ID Name + Type Last Value Last Report Time @@ -130,6 +140,7 @@ {{.getId()}} {{.getName()}} + {{.getDataType()}} {{.getLastValue()}} {{.getLastReportTime().getTimeInMillis()}} @@ -168,6 +179,7 @@ ID Name + Type Last Value Last Report Time @@ -176,6 +188,7 @@ {{.getId()}} {{.getName()}} + {{.getDataType()}} {{.getLastValue()}} {{.getLastReportTime().getTimeInMillis()}} diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigbeeController.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigbeeController.java index f0a62a56..bf7b1e6a 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigbeeController.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigbeeController.java @@ -231,6 +231,10 @@ public class ZigbeeController implements HalSensorController, // Zigbee Node Methods // ------------------------------------------ + public void unPairNode(ZigBeeNode node) { + networkManager.leave(node.getNetworkAddress(), node.getIeeeAddress(), true); + } + @Override public void deviceStatusUpdate(ZigBeeNodeStatus deviceStatus, Integer networkAddress, IeeeAddress ieeeAddress) { logger.fine("New device connected to network: " + ieeeAddress + "(" + deviceStatus + ")"); @@ -402,7 +406,7 @@ public class ZigbeeController implements HalSensorController, public void attributeUpdated(ZclAttribute attribute, Object value) { logger.finer("[Node: " + endpoint.getIeeeAddress() + ", Endpoint: " + endpoint.getEndpointId() + ", Cluster: " + attribute.getCluster().getId() + "] Attribute " + config.getClass().getSimpleName() + " updated: id=" + attribute.getId() + ", attribute_name=" + attribute.getName() + ", value=" + attribute.getLastValue()); - HalDeviceData data = config.getDeviceData(attribute); + HalDeviceData data = config.getDeviceData(endpoint, attribute); if (data != null) { for (HalDeviceReportListener deviceListener : deviceListeners) { deviceListener.reportReceived(config, data); diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeColorConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeColorConfig.java new file mode 100644 index 00000000..71b63aa6 --- /dev/null +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeColorConfig.java @@ -0,0 +1,84 @@ +package se.hal.plugin.zigbee.device; + +import com.zsmartsystems.zigbee.ZigBeeEndpoint; +import com.zsmartsystems.zigbee.zcl.ZclAttribute; +import com.zsmartsystems.zigbee.zcl.ZclCluster; +import com.zsmartsystems.zigbee.zcl.ZclCommand; +import com.zsmartsystems.zigbee.zcl.clusters.ZclColorControlCluster; +import com.zsmartsystems.zigbee.zcl.clusters.colorcontrol.MoveToColorCommand; +import se.hal.intf.HalDeviceData; +import se.hal.intf.HalEventConfig; +import se.hal.intf.HalEventData; +import se.hal.struct.devicedata.ColorEventData; +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 ZigbeeColorConfig extends ZigbeeHalEventDeviceConfig implements HalEventConfig { + private static final Logger logger = LogUtil.getLogger(); + + // -------------------------- + // Zigbee Methods + // -------------------------- + + @Override + public void initialize(ZclCluster cluster) { + if (! (cluster instanceof ZclColorControlCluster)) + return; + + try { + ZclAttribute attribute = cluster.getAttribute(ZclColorControlCluster.ATTR_CURRENTHUE); + attribute.setReporting(1, 900).get(); + attribute.readValue(60); + + attribute = cluster.getAttribute(ZclColorControlCluster.ATTR_CURRENTSATURATION); + 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(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && + (zclAttribute.getId() == ZclColorControlCluster.ATTR_CURRENTHUE || + zclAttribute.getId() == ZclColorControlCluster.ATTR_CURRENTSATURATION)) { + + ZclCluster cluster = endpoint.getInputCluster(zclAttribute.getClusterType().getId()); + float hue = (Integer) cluster.getAttribute(ZclColorControlCluster.ATTR_CURRENTHUE).getLastValue(); + float saturation = (Integer) cluster.getAttribute(ZclColorControlCluster.ATTR_CURRENTSATURATION).getLastValue(); + return ColorEventData.createFromHLS( + hue, 0.5f, saturation, + zclAttribute.getLastReportTime().getTimeInMillis()); + } + return null; + } + + @Override + public int getZigbeeClusterId() { + return ZclColorControlCluster.CLUSTER_ID; + } + + @Override + protected ZclCommand getZigbeeCommandObject(HalEventData data) { + if (! (data instanceof ColorEventData)) + return null; + + float[] cieXYZ = ((ColorEventData) data).getCieXYZ(); + return new MoveToColorCommand((int) cieXYZ[0], (int) cieXYZ[1], 1); + } + + // -------------------------- + // Hal Methods + // -------------------------- + + @Override + public Class getDeviceDataClass() { + return ColorEventData.class; + } +} diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceConfig.java index 5f8f0657..a93012c6 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceConfig.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceConfig.java @@ -66,10 +66,11 @@ public abstract class ZigbeeHalDeviceConfig implements HalDeviceConfig { public void initialize(ZclCluster cluster) {} /** + * @param endpoint * @param zclAttribute is the object that should be mapped to a HalDeviceFata object. * @return a HalDeviceData object containing the same value representation as the endpoint or null if this attribute is not translatable. */ - public abstract HalDeviceData getDeviceData(ZclAttribute zclAttribute); + public abstract HalDeviceData getDeviceData(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute); /** * @return the cluster ID that is supported by this device config class diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceFactory.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceFactory.java index b54226fc..35e34475 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceFactory.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHalDeviceFactory.java @@ -15,8 +15,10 @@ public class ZigbeeHalDeviceFactory { private static final HashMap> clusterDeviceMap = new HashMap<>(); static { + clusterDeviceMap.put(new ZigbeeColorConfig().getZigbeeClusterId(), ZigbeeColorConfig.class); clusterDeviceMap.put(new ZigbeeHumidityConfig().getZigbeeClusterId(), ZigbeeHumidityConfig.class); clusterDeviceMap.put(new ZigbeeIlluminanceConfig().getZigbeeClusterId(), ZigbeeIlluminanceConfig.class); + clusterDeviceMap.put(new ZigbeeLevelConfig().getZigbeeClusterId(), ZigbeeLevelConfig.class); clusterDeviceMap.put(new ZigbeeOccupancyConfig().getZigbeeClusterId(), ZigbeeOccupancyConfig.class); clusterDeviceMap.put(new ZigbeeOnOffConfig().getZigbeeClusterId(), ZigbeeOnOffConfig.class); clusterDeviceMap.put(new ZigbeePressureConfig().getZigbeeClusterId(), ZigbeePressureConfig.class); diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHumidityConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHumidityConfig.java index 0e1fb1eb..f995765a 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHumidityConfig.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeHumidityConfig.java @@ -1,11 +1,11 @@ package se.hal.plugin.zigbee.device; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.clusters.ZclRelativeHumidityMeasurementCluster; import se.hal.intf.HalDeviceData; import se.hal.intf.HalSensorConfig; import se.hal.struct.devicedata.HumiditySensorData; -import se.hal.struct.devicedata.TemperatureSensorData; /** * A device configuration for a specific endpoint on a Zigbee device. @@ -17,8 +17,8 @@ public class ZigbeeHumidityConfig extends ZigbeeHalDeviceConfig implements HalSe // -------------------------- @Override - public HalDeviceData getDeviceData(ZclAttribute zclAttribute) { - if (zclAttribute.getCluster().getId() == getZigbeeClusterId() && + public HalDeviceData getDeviceData(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && zclAttribute.getId() == ZclRelativeHumidityMeasurementCluster.ATTR_MEASUREDVALUE) return new HumiditySensorData( ((int) zclAttribute.getLastValue()) / 100.0, diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeIlluminanceConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeIlluminanceConfig.java index e005fbd9..6ea7b555 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeIlluminanceConfig.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeIlluminanceConfig.java @@ -1,5 +1,6 @@ package se.hal.plugin.zigbee.device; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.clusters.ZclIlluminanceMeasurementCluster; import se.hal.intf.HalDeviceData; @@ -16,8 +17,8 @@ public class ZigbeeIlluminanceConfig extends ZigbeeHalDeviceConfig implements Ha // -------------------------- @Override - public HalDeviceData getDeviceData(ZclAttribute zclAttribute) { - if (zclAttribute.getCluster().getId() == getZigbeeClusterId() && + public HalDeviceData getDeviceData(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && zclAttribute.getId() == ZclIlluminanceMeasurementCluster.ATTR_MEASUREDVALUE) return new IlluminanceSensorData( (int) zclAttribute.getLastValue(), diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeLevelConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeLevelConfig.java new file mode 100644 index 00000000..0993c356 --- /dev/null +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeLevelConfig.java @@ -0,0 +1,73 @@ +package se.hal.plugin.zigbee.device; + +import com.zsmartsystems.zigbee.ZigBeeEndpoint; +import com.zsmartsystems.zigbee.zcl.ZclAttribute; +import com.zsmartsystems.zigbee.zcl.ZclCluster; +import com.zsmartsystems.zigbee.zcl.ZclCommand; +import com.zsmartsystems.zigbee.zcl.clusters.ZclLevelControlCluster; +import com.zsmartsystems.zigbee.zcl.clusters.levelcontrol.MoveToLevelCommand; +import se.hal.intf.HalDeviceData; +import se.hal.intf.HalEventConfig; +import se.hal.intf.HalEventData; +import se.hal.struct.devicedata.LevelEventData; +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 ZigbeeLevelConfig extends ZigbeeHalEventDeviceConfig implements HalEventConfig { + private static final Logger logger = LogUtil.getLogger(); + + // -------------------------- + // Zigbee Methods + // -------------------------- + + @Override + public void initialize(ZclCluster cluster) { + if (! (cluster instanceof ZclLevelControlCluster)) + return; + + try { + ZclAttribute attribute = cluster.getAttribute(ZclLevelControlCluster.ATTR_CURRENTLEVEL); + 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(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && + zclAttribute.getId() == ZclLevelControlCluster.ATTR_CURRENTLEVEL) + return new LevelEventData( + (Integer) zclAttribute.getLastValue(), + zclAttribute.getLastReportTime().getTimeInMillis()); + return null; + } + + @Override + public int getZigbeeClusterId() { + return ZclLevelControlCluster.CLUSTER_ID; + } + + @Override + protected ZclCommand getZigbeeCommandObject(HalEventData data) { + if (! (data instanceof LevelEventData)) + return null; + + return new MoveToLevelCommand((int) (data.getData() * 255), 1); + } + + // -------------------------- + // Hal Methods + // -------------------------- + + @Override + public Class getDeviceDataClass() { + return LevelEventData.class; + } +} diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOccupancyConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOccupancyConfig.java index 618f0193..c1b8bc1d 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOccupancyConfig.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOccupancyConfig.java @@ -1,5 +1,6 @@ package se.hal.plugin.zigbee.device; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.ZclCluster; import com.zsmartsystems.zigbee.zcl.clusters.ZclOccupancySensingCluster; @@ -37,8 +38,8 @@ public class ZigbeeOccupancyConfig extends ZigbeeHalEventDeviceConfig implements } @Override - public HalDeviceData getDeviceData(ZclAttribute zclAttribute) { - if (zclAttribute.getCluster().getId() == getZigbeeClusterId() && + public HalDeviceData getDeviceData(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && zclAttribute.getId() == ZclOccupancySensingCluster.ATTR_OCCUPANCY) return new OccupancyEventData( (boolean) zclAttribute.getLastValue(), diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOnOffConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOnOffConfig.java index 85b20042..2b06717c 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOnOffConfig.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeOnOffConfig.java @@ -1,5 +1,6 @@ package se.hal.plugin.zigbee.device; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.ZclCluster; import com.zsmartsystems.zigbee.zcl.ZclCommand; @@ -40,8 +41,8 @@ public class ZigbeeOnOffConfig extends ZigbeeHalEventDeviceConfig implements Hal } @Override - public HalDeviceData getDeviceData(ZclAttribute zclAttribute) { - if (zclAttribute.getCluster().getId() == getZigbeeClusterId() && + public HalDeviceData getDeviceData(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && zclAttribute.getId() == ZclOnOffCluster.ATTR_ONOFF) return new OnOffEventData( (boolean) zclAttribute.getLastValue(), diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeePressureConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeePressureConfig.java index 93b9a851..5764a540 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeePressureConfig.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeePressureConfig.java @@ -1,5 +1,6 @@ package se.hal.plugin.zigbee.device; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.clusters.ZclTemperatureMeasurementCluster; import se.hal.intf.HalDeviceData; @@ -16,8 +17,8 @@ public class ZigbeePressureConfig extends ZigbeeHalDeviceConfig implements HalSe // -------------------------- @Override - public HalDeviceData getDeviceData(ZclAttribute zclAttribute) { - if (zclAttribute.getCluster().getId() == getZigbeeClusterId() && + public HalDeviceData getDeviceData(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && zclAttribute.getId() == ZclTemperatureMeasurementCluster.ATTR_MEASUREDVALUE) return new PressureSensorData( (int) zclAttribute.getLastValue(), diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeTemperatureConfig.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeTemperatureConfig.java index c66a05c8..cb155042 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeTemperatureConfig.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/device/ZigbeeTemperatureConfig.java @@ -1,5 +1,6 @@ package se.hal.plugin.zigbee.device; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.clusters.ZclTemperatureMeasurementCluster; import se.hal.intf.HalDeviceData; @@ -17,8 +18,8 @@ public class ZigbeeTemperatureConfig extends ZigbeeHalDeviceConfig implements Ha // -------------------------- @Override - public HalDeviceData getDeviceData(ZclAttribute zclAttribute) { - if (zclAttribute.getCluster().getId() == getZigbeeClusterId() && + public HalDeviceData getDeviceData(ZigBeeEndpoint endpoint, ZclAttribute zclAttribute) { + if (zclAttribute.getClusterType().getId() == getZigbeeClusterId() && zclAttribute.getId() == ZclTemperatureMeasurementCluster.ATTR_MEASUREDVALUE) return new TemperatureSensorData( ((int) zclAttribute.getLastValue()) / 100.0, diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/page/ZigbeeNetworkPage.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/page/ZigbeeNetworkPage.java index 695efbca..127d792a 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/page/ZigbeeNetworkPage.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/page/ZigbeeNetworkPage.java @@ -62,6 +62,11 @@ public class ZigbeeNetworkPage extends HalWebPage { } switch (request.get("action")) { + case "node_remove": + if (node != null) + controller.unPairNode(node); + break; + case "refresh": if (attribute != null) attribute.readValue(0); diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/plugin.json b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/plugin.json index 40b91132..47e53951 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/plugin.json +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/plugin.json @@ -5,9 +5,11 @@ "interfaces": [ {"se.hal.intf.HalDatabaseUpgrader": "se.hal.plugin.zigbee.db.ZigbeeHalDatabaseUpgrader"}, + {"se.hal.intf.HalEventConfig": "se.hal.plugin.zigbee.device.ZigbeeColorConfig"}, {"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.ZigbeeLevelConfig"}, {"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"},