From ef40dd52edf563eeeaccf228314fd5ff784442c6 Mon Sep 17 00:00:00 2001 From: Markus Eckhardt Date: Thu, 21 Nov 2019 19:23:16 +0100 Subject: [PATCH] New: openHAB SEMP Service This service implements the SEMP protocol for openHAB Signed-off-by: Markus Eckhardt --- bundles/org.openhab.io.semp/.classpath | 32 -- bundles/org.openhab.io.semp/README.md | 315 -------------- .../noEmbedDependencies.profile | 0 bundles/org.openhab.io.semp/pom.xml | 15 - .../src/main/feature/feature.xml | 10 - .../io/semp/internal/SEMPCapabilities.java | 145 ------- .../io/semp/internal/SEMPCharacteristics.java | 116 ----- .../io/semp/internal/SEMPCommandServlet.java | 240 ----------- .../io/semp/internal/SEMPConstants.java | 121 ------ .../io/semp/internal/SEMPConsumer.java | 369 ---------------- .../io/semp/internal/SEMPDeviceStatus.java | 330 --------------- .../io/semp/internal/SEMPIdentification.java | 204 --------- .../openhab/io/semp/internal/SEMPItem.java | 86 ---- .../semp/internal/SEMPItemCommunication.java | 292 ------------- .../openhab/io/semp/internal/SEMPServlet.java | 304 -------------- .../io/semp/internal/SEMPTimeFrame.java | 219 ---------- .../io/semp/internal/SEMPUpnpServer.java | 302 ------------- .../io/semp/internal/SEMPXmlTools.java | 396 ------------------ .../main/resources/ESH-INF/config/config.xml | 21 - bundles/pom.xml | 1 - 20 files changed, 3518 deletions(-) delete mode 100644 bundles/org.openhab.io.semp/.classpath delete mode 100644 bundles/org.openhab.io.semp/README.md delete mode 100644 bundles/org.openhab.io.semp/noEmbedDependencies.profile delete mode 100644 bundles/org.openhab.io.semp/pom.xml delete mode 100644 bundles/org.openhab.io.semp/src/main/feature/feature.xml delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCapabilities.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCharacteristics.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCommandServlet.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConstants.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConsumer.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPDeviceStatus.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPIdentification.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItem.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItemCommunication.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPServlet.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPTimeFrame.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPUpnpServer.java delete mode 100644 bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPXmlTools.java delete mode 100644 bundles/org.openhab.io.semp/src/main/resources/ESH-INF/config/config.xml diff --git a/bundles/org.openhab.io.semp/.classpath b/bundles/org.openhab.io.semp/.classpath deleted file mode 100644 index a5d95095ccaaf..0000000000000 --- a/bundles/org.openhab.io.semp/.classpath +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bundles/org.openhab.io.semp/README.md b/bundles/org.openhab.io.semp/README.md deleted file mode 100644 index 9d264f2c25f6b..0000000000000 --- a/bundles/org.openhab.io.semp/README.md +++ /dev/null @@ -1,315 +0,0 @@ -# openHAB SEMP Service - -This service implements the SEMP protocol for openHAB - -## Features: - -* UPNP automatic discovery -* Full SEMP Support -* Support ON/OFF and Decimal item types - -## Installation: - -After the activation of this plugin and the configuration of the consumer(s) the upnp service will start immediately. After some minutes you can start a device search in the SMA Sunny Portal. It will detect the device(s) and you will be able to add it to your device list. - -## Configuration: - -An UUID (Universal Unique Identifier) is a 128-bit number used to uniquely identify some object or entity on the Internet. Usually it's a mac and time based V1 UUID but it is possible to use a random generated UUID, too. There are some generators in the internet available. -Important: if you change it then you have to recreate the consumers in SMA Sunny Portal. - -``` -org.openhab.semp:discoveryUUID=8e75f1cc-848e-40ca-b7ec-87369019bd10 -``` - -(Optional) For systems with multiple IP addresses the IP to use for UPNP may be specified, otherwise the first non loopback address will be used. - -``` -org.openhab.semp:discoveryIp=192.168.1.100 -``` - -(Optional) Some SEMP applications require a different port (80) then what openHAB runs on by default (8080). This option will only advertise a different port then what we are listening on. Useful if you have an iptables rule redirect traffic from this port to the openHAB port. - - -``` -org.openhab.semp:discoveryHttpPort=8080 -``` - -## Persistence (Optional) - -Usually this plugin will send the devices status every minute. But there is the possibility to send values up to the last 10 minutes, too. If you want to use this feature then you have to configure persistence for this item. If your persistence is supporting a step smaller then one minute then this plugin will determine additional values like min, max or average from the last 60 seconds. - - -## Device Tagging - -The SEMP service supports multiple consumers. Every SEMP consumer needs up to four items mapped inside one group. These items are a switch item (on/off) for device controlling, a number item (power), an optional contact item for the “Connected” state and an optional contact item for the “Listening” state. -The identification of a SEMP consumer is a group-tag [“Consumer”]. The identification for the consumers items is a tag with the name of the consumers group. These “contact” items has to be tagged for identification, too. Use the [“Connected”] tag for the indication whether the consumer is connected (like a car on an EVCharger) and the [“Listening”] Tag for the indication whether the consumer is listening to the SEMP commands. (e.g. you should set it to open if you are charging a car manually without SEMP). - -## Consumer Configuration - -The consumer need some configuration parameters. This parameters are tags for the group item, too. - -All tags are formatted like this: - -``` -semp:: -``` - -For example: - -``` -semp:max_power:1400 -``` - -If you've defined your Items in _.items_ files, tags can be added using: - -``` -[ "mytag" ] -``` - -syntax (after the _(Groups)_ and before the _{channel}_). -If you created your items another way, e.g. using the Paper UI, [HABmin](https://github.com/openhab/org.openhab.ui.habmin) allows you to modify the tags. - -### Tag: _device___id_ - -The device ID is represented by a 92 bit integer which consists of the following components: -Device ID (92 bits): - -``` -Vendor ID type (4 bits) + Vendor ID (32 bits) + Serial-number (48 bits) + Sub-device ID (8 bits) -``` - -_Required_: no
-_Default_: auto-generated from consumers name
-Example: - -``` -semp:device_id:F-11223344-112233445566-00 -``` - -### Tag: _device___vendor_ - -Name of the device’s vendor. - -_Required_: no
-_Default_: Unknown
-Example: - -``` -semp:device_vendor:Unknown -``` - -### Tag: _device___type_ - -Type of device. One of the values predefined in the SEMP XSD should be used: - -``` -AirConditioning -Charger -DishWasher -Dryer -ElectricVehicle -EVCharger -Fridge -Heater -HeatPump -Motor -Pump -WashingMachine -Other -``` - -_Required_: no
-_Default_: Other
-Example: - -``` -semp:device_type:WashingMachine -``` - -### Tag: _device___serial_ - -A serial number that is known by the user so that he is able -to identify the device. If available use the vendor specific serial number which is printed on -the device. - -_Required_: yes
- -Example: - -``` -semp:device_serial:abc123456789 -``` - -### Tag: _max___power_ - - Maximum power consumption of the device (in W). - -_Required_: yes
- -Example: - -``` -semp:max_power:1400 -``` - -### Tag: _min____off____time_ - -When switched off (or paused), the device has to remain off for at least the given amount -of seconds. - -_Required_: no
-_Default_: 0
-Example: - -``` -semp:min_off_time:15 -``` - -### Tag: _min____on____time_ - -When switched on (or un-paused), the device has to remain on for at least the given -amount of seconds. - -_Required_: no
-_Default_: 0
-Example: - -``` -semp:min_on_time:15 -``` - -### Tag: _inter___alowed_ - -Specifies whether the device can be interrupted (paused) during runtime. This -allows a more flexible energy management for the device. For instance the EM -can interrupt a device in case of unpredictable bad weather conditions or when -the user switches on a device with conflicting energy needs and restart the inter- -rupted device afterwards. - -Should be set to “true”. Set to “false” only if the device operation cannot be -paused, e.g. for some program based devices. - -_Required_: no
-_Default_: true
-Example: - -``` -semp:inter_alowed:true -``` - -### Tag: _earliest___start_ - -Specifies the earliest start time [in minutes from midnight] of the device. - -_Required_: yes
- -Example: - -``` -semp:earliest_start:600 -600->every day at 10am -``` - -If you want multiple time frames then you need to separate them with":" - -``` -semp:earliest_start:600:1020 -``` - - -### Tag: _latest___end_ - -Specifies the end of the planning range. This is the latest possible time the device opera- -tion has to be finished. [in minutes from midnight] - -_Required_: yes
- -Example: - -``` -semp:latest_end:660 -660->every day at 11am -``` - -If you want multiple time frames then you need to separate them with":" - -``` -semp:latest_end:660:1080 -``` - -### Tag: _min____running____time_ - -The minimum amount of time the device needs to run in the time range specified by Earli- -estStart and LatestEnd. It will be assigned to device by the EM even if there is no PV- -production so that grid-energy has to be used to power the device. Note: If set to “0” -all of the energy is optional and should only be allocated to the device if certain -conditions are fulfilled (e.g. cheap PV-energy available). [in minutes] - -_Required_: yes
- -Example: - -``` -semp:min_running_time:30 -``` - -If you want multiple time frames then you need to separate them with":" - -``` -semp:min_running_time:30:20 -``` - -### Tag: _max____running____time_ - -The maximum amount of time the device needs to run in the time range specified by Earli- -estStart and LatestEnd. The difference between MaxRunningTime and MinRunningTime is -the optional runtime that can be assigned to the device by the EM if cheap energy (e.g. -excess PV-energy) is available. [in minutes] - -_Required_: yes
- -Example: - -``` -semp:max_running_time:50 -``` - -If you want multiple time frames then you need to separate them with":" - -``` -semp:max_running_time:50:40 -``` - -### Tag: days___of___week - -Some consumers didn’t have to run every day. Meybe only on the weekdays or on the weekend. With this parameter it’s possible to set the relevant days of the week. These days have to be set in short format, Mon, Tue, Wed, Thu, Fri, Sat, Sun. - -_Required_: no - -Example: - -``` -semp:days_of_week:Mon -``` - -If you want multiple days then you need to separate them with":" - -``` -semp:days_of_week:Mon,Wed,Fri -``` - - -## Example - -demo.items: - -``` -Group PwrSwitchMedia "PowerSwitchMedia" ["Consumer","semp:device_serial:abc123456789","semp:max_power:1400","semp:earliest_start:600","semp:latest_end:1000","semp:min_running_time:0","semp:max_running_time:300"] - -Switch Media_Switch "Media center switch" (PwrSwitchMedia) { knx="<3/1/4" } -Number Media_Power "Media center power" (PwrSwitchMedia) { channel="edimax:sp2101w:29a0126d:power"} - -Contact isListening "Consumer is Listening" (PwrSwitchMedia) ["Listening"] -``` - - diff --git a/bundles/org.openhab.io.semp/noEmbedDependencies.profile b/bundles/org.openhab.io.semp/noEmbedDependencies.profile deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/bundles/org.openhab.io.semp/pom.xml b/bundles/org.openhab.io.semp/pom.xml deleted file mode 100644 index 94c31eda3fef7..0000000000000 --- a/bundles/org.openhab.io.semp/pom.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - 4.0.0 - - - org.openhab.addons.bundles - org.openhab.addons.reactor.bundles - 2.5.0-SNAPSHOT - - - org.openhab.io.semp - - openHAB Add-ons :: Bundles :: IO :: SEMP Service - diff --git a/bundles/org.openhab.io.semp/src/main/feature/feature.xml b/bundles/org.openhab.io.semp/src/main/feature/feature.xml deleted file mode 100644 index 87ad82464c23d..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/feature/feature.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${project.version}/xml/features - - - openhab-runtime-base - openhab-transport-mdns - mvn:org.openhab.addons.bundles/org.openhab.io.semp/${project.version} - - diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCapabilities.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCapabilities.java deleted file mode 100644 index 6dc4c57842fa3..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCapabilities.java +++ /dev/null @@ -1,145 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -/** - * SEMP consumers capabilities - * - * @author Markus Eckhardt - Initial Contribution - * - */ -public class SEMPCapabilities { - /* - * Capability of the device with regard to deriving information about its current power consumption, e.g. - * measurement or estimation - */ - private String method; - - /* - * Bool that indicates if the device is able to deal with absolute timestamps or only with relative timestamps - */ - private Boolean absoluteTimestamps; - - /* - * Specifies if a run of the device can be interrupted or not. - */ - private Boolean interruptionsAllowed; - - /* - * Specifies options related to planning requests. - */ - private Boolean optionalEnergy; - - public SEMPCapabilities() { - } - - /* - * Setter for method - */ - public void setMethod(String method) { - this.method = method; - } - - /* - * Getter for method - */ - public String getMethod() { - return method; - } - - /* - * Checks if field method is set - */ - public boolean isMethodSet() { - if (method == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for absoluteTimestamps - */ - public void setAbsoluteTimestamps(boolean absoluteTimestamps) { - this.absoluteTimestamps = absoluteTimestamps; - } - - /* - * Getter for absoluteTimestamps - */ - public boolean getAbsoluteTimestamps() { - return absoluteTimestamps; - } - - /* - * Checks if field absoluteTimestamps is set - */ - public boolean isAbsoluteTimestampsSet() { - if (absoluteTimestamps == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for interruptionsAllowed - */ - public void setInterruptionsAllowed(boolean interruptionsAllowed) { - this.interruptionsAllowed = interruptionsAllowed; - } - - /* - * Getter for interruptionsAllowed - */ - public boolean getInterruptionsAllowed() { - return interruptionsAllowed; - } - - /* - * Checks if field interruptionsAllowed is set - */ - public boolean isInterruptionsAllowedSet() { - if (interruptionsAllowed == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for optionalEnergy - */ - public void setOptionalEnergy(boolean optionalEnergy) { - this.optionalEnergy = optionalEnergy; - } - - /* - * Getter for optionalEnergy - */ - public boolean getOptionalEnergy() { - return optionalEnergy; - } - - /* - * Checks if field optionalEnergy is set - */ - public boolean isOptionalEnergySet() { - if (optionalEnergy == null) { - return false; - } else { - return true; - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCharacteristics.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCharacteristics.java deleted file mode 100644 index 844db9dec7ecb..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCharacteristics.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -/** - * SEMP consumers characteristics - * - * @author Markus Eckhardt - Initial Contribution - * - */ -public class SEMPCharacteristics { - /* - * Nominal maximum power consumption of the device in Watts. If the device is controllable with regard to power - * consumption, the recommendation - * of the energy management system will never exceed this value. - */ - private Integer maxPowerConsumption; - - /* - * If the device is switched on, it has to remain in this status for at least MinOnTime seconds. - */ - private Integer minOnTime; /* occurs: 0 .. 1 */ - - /* - * If the device is switched off, it has to remain in this status for at least MinOffTime seconds. - */ - private Integer minOffTime; /* occurs: 0 .. 1 */ - - public SEMPCharacteristics() { - } - - /* - * Setter for maxPowerConsumption - */ - public void setMaxPowerConsumption(int maxPowerConsumption) { - this.maxPowerConsumption = maxPowerConsumption; - } - - /* - * Getter for maxPowerConsumption - */ - public int getMaxPowerConsumption() { - return maxPowerConsumption; - } - - /* - * Checks if field maxPowerConsumption is set - */ - public boolean isMaxPowerConsumptionSet() { - if (maxPowerConsumption == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for minOnTime - */ - public void setMinOnTime(int minOnTime) { - this.minOnTime = minOnTime; - } - - /* - * Getter for minOnTime - */ - public int getMinOnTime() { - return minOnTime; - } - - /* - * Checks if field minOnTime is set - */ - public boolean isMinOnTimeSet() { - if (minOnTime == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for minOffTime - */ - public void setMinOffTime(int minOffTime) { - this.minOffTime = minOffTime; - } - - /* - * Getter for minOffTime - */ - public int getMinOffTime() { - return minOffTime; - } - - /* - * Checks if field minOffTime is set - */ - public boolean isMinOffTimeSet() { - if (minOffTime == null) { - return false; - } else { - return true; - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCommandServlet.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCommandServlet.java deleted file mode 100644 index 53c68ab511edd..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPCommandServlet.java +++ /dev/null @@ -1,240 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.core.Response; - -import org.eclipse.smarthome.core.events.EventPublisher; -import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; -import org.eclipse.smarthome.core.persistence.PersistenceService; -import org.eclipse.smarthome.core.persistence.QueryablePersistenceService; -import org.openhab.io.semp.internal.SEMPConstants.SEMPMessageType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Interface for SSDP/SEMP Informations - * - * @author Markus Eckhardt - Initial Contribution - * - */ -@SuppressWarnings("serial") -public class SEMPCommandServlet extends HttpServlet { - private final Logger logger = LoggerFactory.getLogger(SEMPCommandServlet.class); - private static final String PATH_SEMP = "/semp"; - private static final String SUPPORTED_GROUP_TAG = "Consumer"; - private static final List SUPPORTED_ITEM_TYPES = Arrays.asList("Switch", "Number", "Contact"); - private static final List SUPPORTED_CONTROL_TYPES = Arrays.asList("Switch"); - private static final List SUPPORTED_ENERGY_TYPES = Arrays.asList("Number"); - private static final List SUPPORTED_INPUT_TYPES = Arrays.asList("Contact"); - private static final String TAG_INPUT_IS_CONNECTED = "Connected"; - private static final String TAG_INPUT_IS_LISTENING = "Listening"; - private static final String SEMP_DEVICE_ID = "DeviceId"; - - private EventPublisher eventPublisher; - private ItemRegistry itemRegistry; - private Map persistenceServices = new HashMap<>(); - private Map consumerMap = Collections - .synchronizedMap(new LinkedHashMap()); - private SEMPItemCommunication itemCommunication = new SEMPItemCommunication(); - private SEMPXmlTools xmlTools = new SEMPXmlTools(); - - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String message = null; - String path = req.getRequestURI(); - logger.debug("command {}: {} {} {}", req.getRemoteAddr(), req.getMethod(), path, req.getQueryString()); - if (path.startsWith(PATH_SEMP)) { - String deviceID = ""; - determineSEMPConsumers(); - // remove baseURI and remove trailing '/' if existing - String cmd = path.substring(PATH_SEMP.length()); - if (cmd.endsWith("/")) { - cmd = cmd.substring(0, cmd.length() - 1); - } - if (req.getQueryString() != null && req.getQueryString().startsWith(SEMP_DEVICE_ID)) { - deviceID = req.getQueryString().substring(SEMP_DEVICE_ID.length() + 1); - } - if (req.getMethod().equals(HttpMethod.GET)) { - logger.debug("Com: {} Querry: {} Consumers: {}", cmd, req.getQueryString(), consumerMap.keySet()); - if (!itemCommunication.itemsToDevice(consumerMap, deviceID, persistenceServices)) { - logger.error("Error in item determination"); - resp.setStatus(Response.Status.BAD_REQUEST.getStatusCode()); - return; - } - if ("".equals(cmd)) { - logger.debug("Req /SEMP"); - message = xmlTools.createXMLMessage(Arrays.asList(SEMPMessageType.MSG_DEVICE_INFO, - SEMPMessageType.MSG_DEVICE_STATUS, SEMPMessageType.MSG_TIMEFRAME), consumerMap, deviceID); - } - if ("/DeviceInfo".equals(cmd)) { - message = xmlTools.createXMLMessage(Arrays.asList(SEMPMessageType.MSG_DEVICE_INFO), consumerMap, - deviceID); - } - if ("/DeviceStatus".equals(cmd)) { - message = xmlTools.createXMLMessage(Arrays.asList(SEMPMessageType.MSG_DEVICE_STATUS), consumerMap, - deviceID); - } - if ("/PlanningRequest".equals(cmd)) { - message = xmlTools.createXMLMessage(Arrays.asList(SEMPMessageType.MSG_TIMEFRAME), consumerMap, - deviceID); - } - if (message != null) { - resp.setContentType("application/xml"); - try (PrintWriter out = resp.getWriter()) { - logger.debug("Device /semp: {}", message); - out.write(message); - if (out.checkError()) { - logger.error("Network write error"); - } - } - resp.setStatus(Response.Status.OK.getStatusCode()); - } - } else if (req.getMethod().equals(HttpMethod.POST)) { - ServletInputStream xmlStream = req.getInputStream(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[10240]; - int len; - while ((len = xmlStream.read(buffer)) > -1) { - baos.write(buffer, 0, len); - } - baos.flush(); - deviceID = xmlTools.getXMLValue(new ByteArrayInputStream(baos.toByteArray()), - "/EM2Device/DeviceControl/DeviceId"); - logger.debug("deviceID: {}", deviceID); - String val = xmlTools.getXMLValue(new ByteArrayInputStream(baos.toByteArray()), - "/EM2Device/DeviceControl/On"); - if (deviceID == null || val == null) { - resp.setStatus(Response.Status.BAD_REQUEST.getStatusCode()); - return; - } - logger.debug("Val: {}", val); - synchronized (consumerMap) { - if (!itemCommunication.deviceToItems(consumerMap, Boolean.parseBoolean(val), deviceID, - eventPublisher)) { - resp.setStatus(Response.Status.BAD_REQUEST.getStatusCode()); - return; - } - } - resp.setStatus(Response.Status.OK.getStatusCode()); - } - } - } - - public void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; - } - - public void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; - } - - protected void setEventPublisher(EventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; - } - - protected void unsetEventPublisher(EventPublisher eventPublisher) { - this.eventPublisher = null; - } - - public void addPersistenceService(PersistenceService service) { - if (service instanceof QueryablePersistenceService) { - persistenceServices.put(service.getId(), (QueryablePersistenceService) service); - } - } - - public void removePersistenceService(PersistenceService service) { - persistenceServices.remove(service.getId()); - } - - private void determineSEMPConsumers() { - List actConsumers = new ArrayList(); - List toRemove = new ArrayList(); - - for (Item item : itemRegistry.getItemsByTagAndType("Group", SUPPORTED_GROUP_TAG)) { - logger.debug("Group: {} : {} :{}", item.getName(), item.getLabel(), item.getType()); - actConsumers.add(item.getName()); - SEMPConsumer consumer = new SEMPConsumer(); - if (!consumerMap.containsKey(item.getName())) { - consumerMap.put(item.getName(), consumer); - } - consumerMap.get(item.getName()).setGroupItem(item); - } - for (String consumer : consumerMap.keySet()) { - if (!actConsumers.contains(consumer)) { - toRemove.add(consumer); - } else { - consumerMap.get(consumer).unsetItems(); - } - } - for (String consumer : toRemove) { - consumerMap.remove(consumer); - } - for (String type : SUPPORTED_ITEM_TYPES) { - for (Item item : itemRegistry.getItemsOfType(type)) { - for (String groupName : item.getGroupNames()) { - if (consumerMap.containsKey(groupName)) { - logger.debug("Item: {} Group: {}", item.getName(), groupName); - SEMPConsumer consumer = consumerMap.get(groupName); - if (SUPPORTED_CONTROL_TYPES.contains(type)) { - consumer.setControlItem(item); - } - if (SUPPORTED_ENERGY_TYPES.contains(type)) { - consumer.setEnergyItem(item); - } - if (SUPPORTED_INPUT_TYPES.contains(type)) { - for (String inputType : item.getTags()) { - if (TAG_INPUT_IS_CONNECTED.equals(inputType)) { - logger.debug("Connected Item: {}", item.getName()); - consumer.setConnectionItem(item); - } - if (TAG_INPUT_IS_LISTENING.equals(inputType)) { - logger.debug("Listening Item: {}", item.getName()); - consumer.setListeningItem(item); - } - } - } - } - } - } - } - for (String consumer : consumerMap.keySet()) { - consumerMap.get(consumer).getTimeFrames().clear(); - consumerMap.get(consumer).getDaysOfTheWeek().clear(); - if (!consumerMap.get(consumer).checkItemsTags()) { - consumerMap.remove(consumer); - } else { - consumerMap.get(consumer).setDefaultTags(); - } - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConstants.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConstants.java deleted file mode 100644 index e33d35ed8d40c..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConstants.java +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -import java.util.ArrayList; -import java.util.List; - -/** - * This class defines common constants, which are - * used across the whole binding. - * - * @author Markus Eckhardt - Initial contribution - */ -public class SEMPConstants { - public static final String SEMP_BASE_URL_PATH_DEFAULT = "/semp"; - public static final int SEMP_BASE_URL_PORT_DEFAULT = 80; - public static final String SEMP_DOMAIN_NAME = "schemas-simple-energy-management-protocol"; - public static final String SEMP_DEVICE_TYPE = "Gateway"; - public static final int SEMP_DEVICE_TYPE_VER = 1; - public static final String SEMP_SERVICE_TYPE = "SimpleEnergyManagementProtocol"; - public static final int SEMP_SERVICE_TYPE_VER = 1; - - public static final String SEMP_URN_DEVICE = SEMP_DOMAIN_NAME + ":device:" + SEMP_DEVICE_TYPE + ":" - + SEMP_DEVICE_TYPE_VER; - public static final String SEMP_URN_SERVICE = SEMP_DOMAIN_NAME + ":service:" + SEMP_SERVICE_TYPE + ":" - + SEMP_SERVICE_TYPE_VER; - - public static final String SSDP_MCAST_IP = "239.255.255.250"; - public static final int SSDP_MCAST_PORT = 1900; - public static final String SSDP_SERVER_TYPE = "Linux/2.6.32 UPnP/1.0 SMA SSDP Server/1.0.0"; - public static final int SSDP_VALIDITY_PERIOD = 120; - - public static final String SEMP_XSD_VERSION = "1.1.5"; - public static final String GATEWAY_SERIAL = "43-4D-43-4D-11-FF"; - - public static final int DEFAULT_GATEWAY_HTTP_PORT = 8080; - - public static final List SSDP_SERVICE_CONFIG_LIST = new ArrayList(); - - public static final SEMPDeviceConfig SEMP_DEVICE_CONFIG = new SEMPDeviceConfig(); - - public static enum SSDPDiscoveryType { - SSDP_DT_ROOTDEVICE, - SSDP_DT_DEVICE_TYPE, - SSDP_DT_DEVICEID_TYPE, - SSDP_DT_SERVICE_TYPE, - }; - - enum SEMPMessageType { - MSG_SEMP_INFO, - MSG_DEVICE_INFO, - MSG_DEVICE_STATUS, - MSG_TIMEFRAME - }; - - public static final class SEMPDeviceConfig { - public String urn; // device-type URN. Format: "[schemas-upnp-org|]:device::" (no - // "urn:"-prefix) - public String friendlyName; - public String manufacturer; - public String manufacturerURL; - public String modelDescription; - public String modelName; - public String modelNumber; - public String modelURL; - public String serialNumber; - public String presentationURL; - public List additionalElements = new ArrayList(); - - public SEMPDeviceConfig() { - this.urn = SEMP_URN_DEVICE; - this.friendlyName = "SimpleEnergyManagementProtocol Gateway"; - this.manufacturer = "openHAB"; - this.manufacturerURL = "http://www.openHAB.org"; - this.modelDescription = "openHAB SimpleEnergyManagementProtocol Gateway"; - this.modelName = "org.binding.io.semp"; - this.modelNumber = "1.0.0"; - this.modelURL = "http://www.openHAB.org"; - this.serialNumber = GATEWAY_SERIAL; - this.presentationURL = "presentation.html"; - additionalElements.add("\n"); - additionalElements - .add("\thttp://@IFACE_ADDR@:" + DEFAULT_GATEWAY_HTTP_PORT + "\n"); - additionalElements.add("\t" + SEMP_BASE_URL_PATH_DEFAULT + "\n"); - additionalElements.add("\tHTTP/Pull\n"); - additionalElements.add("\tXML\n"); - additionalElements.add("\t" + SEMP_XSD_VERSION + "\n"); - additionalElements.add("\n"); - SSDP_SERVICE_CONFIG_LIST.add(new SSDPServiceConfig(SEMP_DOMAIN_NAME + ":service:NULL:1", - SEMP_DOMAIN_NAME + ":serviceId:NULL", "/XD/NULL.xml", "/UD/?0", "")); - } - } - - public static final class SSDPServiceConfig { - public String typeUrn; // service-type URN. Format: - // "[schemas-upnp-org|]:service::"(no "urn:"-prefix) - public String idUrn; // service-Id URN. Format: "[upnp-org|]:serviceId:" (no - // "urn:"-prefix) - public String serviceDescriptorURL; // URL to service descriptor - public String controlURL; // URL for control - public String eventSubURL; // URL for eventing - - public SSDPServiceConfig(String typeUrn, String idUrn, String SCPDURL, String controlURL, String eventSubURL) { - this.typeUrn = typeUrn; - this.idUrn = idUrn; - this.serviceDescriptorURL = SCPDURL; - this.controlURL = controlURL; - this.eventSubURL = eventSubURL; - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConsumer.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConsumer.java deleted file mode 100644 index afc2cda526f3d..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPConsumer.java +++ /dev/null @@ -1,369 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.smarthome.core.items.Item; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class is representing a SEMP electrical consumer - * - * @author Markus Eckhardt - Initial contribution - */ -public class SEMPConsumer { - private final Logger logger = LoggerFactory.getLogger(SEMPConsumer.class); - private static final String PREFIX_SEMP = "semp:"; - private static final String PREFIX_SEMP_DEVICE_ID = PREFIX_SEMP + "device_id:"; - private static final String PREFIX_SEMP_DEVICE_VENDOR = PREFIX_SEMP + "device_vendor:"; - private static final String PREFIX_SEMP_DEVICE_TYPE = PREFIX_SEMP + "device_type:"; - private static final String PREFIX_SEMP_SERIAL = PREFIX_SEMP + "device_serial:"; - private static final String PREFIX_SEMP_MAX_POWER = PREFIX_SEMP + "max_power:"; - private static final String PREFIX_SEMP_MIN_OFF_TIME = PREFIX_SEMP + "min_off_time:"; - private static final String PREFIX_SEMP_MIN_ON_TIME = PREFIX_SEMP + "min_on_time:"; - private static final String PREFIX_SEMP_METHOD = PREFIX_SEMP + "method"; - private static final String PREFIX_SEMP_INTER_ALOWED = PREFIX_SEMP + "inter_alowed:"; - private static final String PREFIX_SEMP_EARLIEST_START = PREFIX_SEMP + "earliest_start:"; - private static final String PREFIX_SEMP_LATEST_END = PREFIX_SEMP + "latest_end:"; - private static final String PREFIX_SEMP_MIN_RUNNING_TIME = PREFIX_SEMP + "min_running_time:"; - private static final String PREFIX_SEMP_MAX_RUNNING_TIME = PREFIX_SEMP + "max_running_time:"; - private static final String PREFIX_SEMP_RUNNING_WEEKDAYS = PREFIX_SEMP + "days_of_week:"; - - private static final List ALOWED_DEVICE_TYPES = Arrays.asList("AirConditioning", "Charger", "DishWasher", - "Dryer", "ElectricVehicle", "EVCharger", "Fridge", "Heater", "HeatPump", "Motor", "Pump", "WashingMachine", - "Other"); - - private SEMPIdentification identification = new SEMPIdentification(); - private SEMPCharacteristics characteristics = new SEMPCharacteristics(); - private SEMPCapabilities capabilities = new SEMPCapabilities(); - private SEMPDeviceStatus deviceStatus = new SEMPDeviceStatus(); - private List timeFrames = new ArrayList(); - private List deviceHistoryStatus = new ArrayList(); - private List daysOfTheWeek = new ArrayList(); - public boolean hasHistory = false; - - private Item controlItem; - private Item energyItem; - private Item groupItem; - private Item isConnectedItem; - private Item isListeningItem; - - public SEMPConsumer() { - } - - public void unsetItems() { - controlItem = null; - energyItem = null; - isConnectedItem = null; - isListeningItem = null; - } - - public SEMPIdentification getIdentification() { - return identification; - } - - public SEMPCharacteristics getCharacteristics() { - return characteristics; - } - - public SEMPCapabilities getCapabilities() { - return capabilities; - } - - public SEMPDeviceStatus getDeviceStatus() { - return deviceStatus; - } - - public List getTimeFrames() { - return timeFrames; - } - - public List getDeviceHistoryStatus() { - return deviceHistoryStatus; - } - - public List getDaysOfTheWeek() { - return daysOfTheWeek; - } - - public Item getGroupItem() { - return groupItem; - } - - public Item getControlItem() { - return controlItem; - } - - public Item getEnergyItem() { - return energyItem; - } - - public Item getConnectionItem() { - return isConnectedItem; - } - - public Item getListeningItem() { - return isListeningItem; - } - - public void setGroupItem(Item groupItem) { - this.groupItem = groupItem; - } - - public void setControlItem(Item controlItem) { - this.controlItem = controlItem; - } - - public void setEnergyItem(Item energyItem) { - this.energyItem = energyItem; - } - - public void setConnectionItem(Item isConnectedItem) { - this.isConnectedItem = isConnectedItem; - } - - public void setListeningItem(Item isListeningItem) { - this.isListeningItem = isListeningItem; - } - - public boolean checkItemsTags() { - String groupLabel = groupItem.getLabel(); - if (groupLabel == null) { - logger.error("{}:Label:No Grouplabel set", groupItem.getName()); - return false; - } else { - getIdentification().setDeviceName(groupLabel); - } - for (String groupTag : groupItem.getTags()) { - if (groupTag.startsWith(PREFIX_SEMP_DEVICE_ID)) { - getIdentification().setDeviceId(groupTag.substring(PREFIX_SEMP_DEVICE_ID.length())); - } - if (groupTag.startsWith(PREFIX_SEMP_DEVICE_VENDOR)) { - getIdentification().setDeviceVendor(groupTag.substring(PREFIX_SEMP_DEVICE_VENDOR.length())); - } - if (groupTag.startsWith(PREFIX_SEMP_DEVICE_TYPE)) { - String devType = groupTag.substring(PREFIX_SEMP_DEVICE_TYPE.length()); - if (ALOWED_DEVICE_TYPES.contains(devType)) { - getIdentification().setDeviceType(devType); - } else { - logger.error("{}:{}:Type is not valid", groupItem.getName(), PREFIX_SEMP_MAX_POWER); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_SERIAL)) { - getIdentification().setDeviceSerial(groupTag.substring(PREFIX_SEMP_SERIAL.length())); - } - if (groupTag.startsWith(PREFIX_SEMP_MAX_POWER)) { - try { - getCharacteristics().setMaxPowerConsumption( - Integer.parseInt(groupTag.substring(PREFIX_SEMP_MAX_POWER.length()))); - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_MAX_POWER, e.getMessage()); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_MIN_OFF_TIME)) { - try { - getCharacteristics() - .setMinOffTime(Integer.parseInt(groupTag.substring(PREFIX_SEMP_MIN_OFF_TIME.length()))); - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_MIN_OFF_TIME, e.getMessage()); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_MIN_ON_TIME)) { - try { - getCharacteristics() - .setMinOnTime(Integer.parseInt(groupTag.substring(PREFIX_SEMP_MIN_ON_TIME.length()))); - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_MIN_ON_TIME, e.getMessage()); - } - } - if (groupTag.startsWith(PREFIX_SEMP_METHOD)) { - getCapabilities().setMethod(groupTag.substring(PREFIX_SEMP_METHOD.length())); - } - if (groupTag.startsWith(PREFIX_SEMP_INTER_ALOWED)) { - try { - getCapabilities().setInterruptionsAllowed( - Boolean.parseBoolean(groupTag.substring(PREFIX_SEMP_INTER_ALOWED.length()))); - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_INTER_ALOWED, e.getMessage()); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_EARLIEST_START)) { - try { - String[] parts = groupTag.substring(PREFIX_SEMP_EARLIEST_START.length()).split(":"); - for (int i = 0; i < parts.length; i++) { - if (getTimeFrames().size() > i) { - getTimeFrames().get(i).setEarliestStart(Integer.parseInt(parts[i]) * 60); - } else { - SEMPTimeFrame timeFrame = new SEMPTimeFrame(); - timeFrame.setEarliestStart(Integer.parseInt(parts[i]) * 60); - getTimeFrames().add(timeFrame); - } - } - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_EARLIEST_START, e.getMessage()); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_LATEST_END)) { - try { - String[] parts = groupTag.substring(PREFIX_SEMP_LATEST_END.length()).split(":"); - for (int i = 0; i < parts.length; i++) { - if (getTimeFrames().size() > i) { - getTimeFrames().get(i).setLatestEnd(Integer.parseInt(parts[i]) * 60); - } else { - SEMPTimeFrame timeFrame = new SEMPTimeFrame(); - timeFrame.setLatestEnd(Integer.parseInt(parts[i]) * 60); - getTimeFrames().add(timeFrame); - } - } - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_LATEST_END, e.getMessage()); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_MIN_RUNNING_TIME)) { - try { - String[] parts = groupTag.substring(PREFIX_SEMP_MIN_RUNNING_TIME.length()).split(":"); - for (int i = 0; i < parts.length; i++) { - if (getTimeFrames().size() > i) { - getTimeFrames().get(i).setMinRunningTime(Integer.parseInt(parts[i]) * 60); - } else { - SEMPTimeFrame timeFrame = new SEMPTimeFrame(); - timeFrame.setMinRunningTime(Integer.parseInt(parts[i]) * 60); - getTimeFrames().add(timeFrame); - } - } - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_MIN_RUNNING_TIME, e.getMessage()); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_MAX_RUNNING_TIME)) { - try { - String[] parts = groupTag.substring(PREFIX_SEMP_MAX_RUNNING_TIME.length()).split(":"); - for (int i = 0; i < parts.length; i++) { - if (getTimeFrames().size() > i) { - getTimeFrames().get(i).setMaxRunningTime(Integer.parseInt(parts[i]) * 60); - } else { - SEMPTimeFrame timeFrame = new SEMPTimeFrame(); - timeFrame.setMaxRunningTime(Integer.parseInt(parts[i]) * 60); - getTimeFrames().add(timeFrame); - } - } - } catch (NumberFormatException e) { - logger.error("{}:{}:{}", groupItem.getName(), PREFIX_SEMP_MAX_RUNNING_TIME, e.getMessage()); - return false; - } - } - if (groupTag.startsWith(PREFIX_SEMP_RUNNING_WEEKDAYS)) { - String[] parts = groupTag.substring(PREFIX_SEMP_RUNNING_WEEKDAYS.length()).split(":"); - for (int i = 0; i < parts.length; i++) { - daysOfTheWeek.add(parts[i]); - } - } - } - return checkTimeFrames(); - } - - public void setDefaultTags() { - this.getCapabilities().setAbsoluteTimestamps(true); - this.getCapabilities().setOptionalEnergy(true); - if (!this.getIdentification().isDeviceIdSet()) { - int hashVal = groupItem.getName().hashCode(); - if (hashVal < 0) { - hashVal *= -1; - } - if (hashVal < 10000000) { - hashVal += 10000000; - } - this.getIdentification().setDeviceId("F-" + String.valueOf(hashVal).substring(0, 8) + "-112233445566-00"); - } - if (!this.getIdentification().isDeviceVendorSet()) { - this.getIdentification().setDeviceVendor("Unknown"); - } - if (!this.getIdentification().isDeviceTypeSet()) { - this.getIdentification().setDeviceType("Other"); - } - if (!this.getCapabilities().isMethodSet()) { - this.getCapabilities().setMethod("Measurement"); - } - if (!this.getCapabilities().isInterruptionsAllowedSet()) { - this.getCapabilities().setInterruptionsAllowed(true); - } - } - - private boolean checkTimeFrames() { - for (int i = getTimeFrames().size() - 1; i >= 0; i--) { - if (getTimeFrames().get(i).getEarliestStart() < 0 || getTimeFrames().get(i).getEarliestStart() > 86400 - || getTimeFrames().get(i).getLatestEnd() < 0 || getTimeFrames().get(i).getLatestEnd() > 86400 - || getTimeFrames().get(i).getMaxRunningTime() < 0 - || getTimeFrames().get(i).getMaxRunningTime() > 86400 - || getTimeFrames().get(i).getMinRunningTime() < 0 - || getTimeFrames().get(i).getMinRunningTime() > 86400) { - logger.error("Alle time frame values has to be between 0 and 1440 minutes"); - getTimeFrames().clear(); - return false; - } - if (getTimeFrames().get(i).getEarliestStart() > getTimeFrames().get(i).getLatestEnd()) { - logger.error("The earliest start has to be smaller then latest end"); - getTimeFrames().clear(); - return false; - } - if (i > 0) { - if (getTimeFrames().get(i).getEarliestStart() < getTimeFrames().get(i - 1).getLatestEnd()) { - logger.error("The end of a time frame has to be smaller or same then the start of the next one"); - getTimeFrames().clear(); - return false; - } - } - if (getTimeFrames().get(i).getMinRunningTime() > getTimeFrames().get(i).getMaxRunningTime()) { - logger.error("The min running time has to be smaller then max running time"); - getTimeFrames().clear(); - return false; - } - if (getTimeFrames().get(i).getMinRunningTime() > (getTimeFrames().get(i).getLatestEnd() - - getTimeFrames().get(i).getEarliestStart())) { - logger.error("The min running time has to be smaller then the planing range"); - getTimeFrames().clear(); - return false; - } - } - return true; - } - - public SEMPTimeFrame getCurrentTimeFrame(long timestamp) { - LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); - long unixDayTime = startOfToday.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(Instant.now())); - for (int i = timeFrames.size() - 1; i >= 0; i--) { - if (timestamp > (timeFrames.get(i).getEarliestStart() + unixDayTime)) { - return timeFrames.get(i); - } - } - if (timestamp < (timeFrames.get(0).getEarliestStart() + unixDayTime)) { - return timeFrames.get(timeFrames.size() - 1); - } - return null; - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPDeviceStatus.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPDeviceStatus.java deleted file mode 100644 index 9da49d8d61f2e..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPDeviceStatus.java +++ /dev/null @@ -1,330 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -/** - * SEMP consumers status - * - * @author Markus Eckhardt - Initial Contribution - */ -public class SEMPDeviceStatus { - /* - * Boolean that indicates if the device is currently considering the control signals or recommendations provided by - * the energy manager or if it is - * in a mode which ignores the signals or recommendations - */ - private Boolean eMSignalsAccepted; - - /* - * String that provides information of the current status of the device (Offline, On, Off). - * See StatusRefType for known values. - */ - private String status; - - /* - * Identifies the current error state of the device. If the code is 0, no error is pending. - */ - private Integer errorCode; /* occurs: 0 .. 1 */ - - /* - * Real average power within the interval in Watts. - */ - private Double averagePower; - - /* - * Minimum power value within the interval in Watts. - */ - private Double minPower; /* occurs: 0 .. 1 */ - - /* - * Maximum power within the interval in Watts. - */ - private Double maxPower; /* occurs: 0 .. 1 */ - - /* - * Timestamp that represents the end of the averaging interval. - * Although this element is marked as optional it is mandatory in PowerConsumption:PowerInfo. - */ - private Long timestamp; - - /* - * Length of the averaging interval in seconds. - * Although this element is marked as optional it is mandatory in PowerConsumption:PowerInfo. - */ - private Integer averagingInterval; - - /* - * Standard deviation within the interval in Watts. - */ - private Double stdDevPower; - - /* - * Skewness within the interval in Watts. - */ - private Double skewPower; - - public SEMPDeviceStatus() { - } - - /* - * Setter for eMSignalsAccepted - */ - public void setEMSignalsAccepted(boolean eMSignalsAccepted) { - this.eMSignalsAccepted = eMSignalsAccepted; - } - - /* - * Getter for eMSignalsAccepted - */ - public boolean getEMSignalsAccepted() { - return eMSignalsAccepted; - } - - /* - * Checks if field eMSignalsAccepted is set - */ - public boolean isEMSignalsAcceptedSet() { - if (eMSignalsAccepted == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for status - */ - public void setStatus(String status) { - this.status = status; - } - - /* - * Getter for status - */ - public String getStatus() { - return status; - } - - /* - * Checks if field status is set - */ - public boolean isStatusSet() { - if (status == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for errorCode - */ - public void setErrorCode(Integer errorCode) { - this.errorCode = errorCode; - } - - /* - * Getter for errorCode - */ - public Integer getErrorCode() { - return errorCode; - } - - /* - * Checks if field errorCode is set - */ - public boolean isErrorCodeSet() { - if (errorCode == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for averagePower - */ - public void setAveragePower(Double averagePower) { - this.averagePower = averagePower; - } - - /* - * Getter for averagePower - */ - public Double getAveragePower() { - return averagePower; - } - - /* - * Checks if field averagePower is set - */ - public boolean isAveragePowerSet() { - if (averagePower == null) { - return false; - } else { - return true; - } - } - - /* - * ! - * - * Setter for minPower - */ - public void setMinPower(Double minPower) { - this.minPower = minPower; - } - - /* - * Getter for minPower - */ - public Double getMinPower() { - return minPower; - } - - /* - * Checks if field minPower is set - */ - public boolean isMinPowerSet() { - if (minPower == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for maxPower - */ - public void setMaxPower(Double maxPower) { - this.maxPower = maxPower; - } - - /* - * Getter for maxPower - */ - public Double getMaxPower() { - return maxPower; - } - - /* - * Checks if field maxPower is set - */ - public boolean isMaxPowerSet() { - if (maxPower == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for RelOrAbsTime - */ - public void setTimestamp(Long timestamp) { - this.timestamp = timestamp; - } - - /* - * Getter for RelOrAbsTime - */ - public Long getTimestamp() { - return timestamp; - } - - /* - * Checks if field RelOrAbsTime is set - */ - public boolean isTimestampSet() { - if (timestamp == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for averagingInterval - */ - public void setAveragingInterval(Integer averagingInterval) { - this.averagingInterval = averagingInterval; - } - - /* - * Getter for averagingInterval - */ - public Integer getAveragingInterval() { - return averagingInterval; - } - - /* - * Checks if field averagingInterval is set - */ - public boolean isAveragingIntervalSet() { - if (averagingInterval == null) { - return false; - } else { - return true; - } - } - - /* - * Checks if field stdDevPower is set - */ - public boolean isStdDevPowerSet() { - if (stdDevPower == null) { - return false; - } else { - return true; - } - } - - /* - * Getter for stdDevPower - */ - public Double getStdDevPower() { - return stdDevPower; - } - - /* - * Setter for stdDevPower - */ - public void setStdDevPower(double stdDevPower) { - this.stdDevPower = stdDevPower; - } - - /* - * Checks if field skewPower is set - */ - public boolean isSkewPowerSet() { - if (skewPower == null) { - return false; - } else { - return true; - } - } - - /* - * Getter for skewPower - */ - public Double getSkewPower() { - return skewPower; - } - - /* - * Setter for skewPower - */ - public void setSkewPower(double skewPower) { - this.skewPower = skewPower; - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPIdentification.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPIdentification.java deleted file mode 100644 index 02cb025a4fdb4..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPIdentification.java +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -/** - * SEMP consumers identification - * - * @author Markus Eckhardt - Initial Contribution - * - */ -public class SEMPIdentification { - /* - * Unique identification of the device. - */ - private String deviceId; - - /* - * Human readable device name - */ - private String deviceName; - - /* - * Human readable type of the device. See DeviceTypeRefType for well-known types. - */ - private String deviceType; - - /* - * Vendor specific serial number of the device - */ - private String deviceSerial; - - /* - * Human readable name of the device vendor - */ - private String deviceVendor; - - /* - * Configuration URL of the device. - */ - private String deviceURL; /* occurs: 0 .. 1 */ - - public SEMPIdentification() { - } - - /* - * Setter for DeviceId - */ - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - /* - * Getter for DeviceId - */ - public String getDeviceId() { - return deviceId; - } - - /* - * Checks if field DeviceId is set - */ - public boolean isDeviceIdSet() { - if (deviceId == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for deviceName - */ - public void setDeviceName(String deviceName) { - this.deviceName = deviceName; - } - - /* - * Getter for deviceName - */ - public String getDeviceName() { - return deviceName; - } - - /* - * Checks if field deviceName is set - */ - public boolean isDeviceNameSet() { - if (deviceName == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for deviceType - */ - public void setDeviceType(String deviceType) { - this.deviceType = deviceType; - } - - /* - * Getter for deviceType - */ - public String getDeviceType() { - return deviceType; - } - - /* - * Checks if field deviceType is set - */ - public boolean isDeviceTypeSet() { - if (deviceType == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for deviceSerial - */ - public void setDeviceSerial(String deviceSerial) { - this.deviceSerial = deviceSerial; - } - - /* - * Getter for deviceSerial - */ - public String getDeviceSerial() { - return deviceSerial; - } - - /* - * Checks if field deviceSerial is set - */ - public boolean isDeviceSerialSet() { - if (deviceSerial == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for deviceVendor - */ - public void setDeviceVendor(String deviceVendor) { - this.deviceVendor = deviceVendor; - } - - /* - * Getter for deviceVendor - */ - public String getDeviceVendor() { - return deviceVendor; - } - - /* - * Checks if field deviceVendor is set - */ - public boolean isDeviceVendorSet() { - if (deviceVendor == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for deviceSerial - */ - public void setDeviceURL(String deviceURL) { - this.deviceURL = deviceURL; - } - - /* - * Getter for deviceSerial - */ - public String getDeviceURL() { - return deviceURL; - } - - /* - * Checks if field deviceSerial is set - */ - public boolean isDeviceURLSet() { - if (deviceURL == null) { - return false; - } else { - return true; - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItem.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItem.java deleted file mode 100644 index c5796db5ea068..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItem.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -/** - * History item data object. - * - * @author Markus Eckhardt - Initial contribution - */ -public class SEMPItem { - - private long timestamp; - private double minPower; - private double maxPower; - private double avPower; - private double stdDevPower; - private double skewPower; - - public SEMPItem(long timestamp, double avPower, double minPower, double maxPower, double stdDevPower, - double skewPower) { - this.timestamp = timestamp; - this.avPower = avPower; - this.minPower = minPower; - this.maxPower = maxPower; - this.stdDevPower = stdDevPower; - this.skewPower = skewPower; - } - - public long getTimestamp() { - return timestamp; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - public double getAvPower() { - return avPower; - } - - public void setAvPower(double avPower) { - this.avPower = avPower; - } - - public double getMinPower() { - return minPower; - } - - public void setMinPower(double minPower) { - this.minPower = minPower; - } - - public double getMaxPower() { - return maxPower; - } - - public void setMaxPower(double maxPower) { - this.maxPower = maxPower; - } - - public double getStdDevPower() { - return stdDevPower; - } - - public void setStdDevPower(double stdDevPower) { - this.stdDevPower = stdDevPower; - } - - public double getSkewPower() { - return skewPower; - } - - public void setSkewPower(double skewPower) { - this.skewPower = skewPower; - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItemCommunication.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItemCommunication.java deleted file mode 100644 index b306f4fef88d2..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPItemCommunication.java +++ /dev/null @@ -1,292 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.eclipse.smarthome.core.events.EventPublisher; -import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.events.ItemEventFactory; -import org.eclipse.smarthome.core.library.types.DecimalType; -import org.eclipse.smarthome.core.library.types.OnOffType; -import org.eclipse.smarthome.core.library.types.OpenClosedType; -import org.eclipse.smarthome.core.persistence.FilterCriteria; -import org.eclipse.smarthome.core.persistence.HistoricItem; -import org.eclipse.smarthome.core.persistence.QueryablePersistenceService; -import org.eclipse.smarthome.core.types.Command; -import org.eclipse.smarthome.core.types.State; -import org.eclipse.smarthome.core.types.TypeParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * SEMP consumers identification - * - * @author Markus Eckhardt - Initial Contribution - * - */ -public class SEMPItemCommunication { - private final Logger logger = LoggerFactory.getLogger(SEMPItemCommunication.class); - - public boolean itemsToDevice(Map consumerMap, String deviceID, - Map persistenceServices) { - List historicValues; - for (SEMPConsumer consumer : consumerMap.values()) { - if (!consumer.getIdentification().getDeviceId().equals(deviceID) && !"".equals(deviceID)) { - continue; - } - if (consumer.getControlItem() == null) { - logger.error("No control item for group {} set", consumer.getGroupItem().getName()); - continue; - } - logger.debug("Reading items state, Group: {}", consumer.getGroupItem().getName()); - boolean isConnected = true; - boolean isListening = true; - if (consumer.getConnectionItem() != null) { - logger.debug("Connection Item availible, state: {}", consumer.getConnectionItem().getState()); - if (consumer.getConnectionItem().getState() == OpenClosedType.OPEN) { - isConnected = false; - isListening = false; - } - } - if (consumer.getListeningItem() != null) { - logger.debug("Listening Item availible, state: {}", consumer.getListeningItem().getState()); - if (consumer.getListeningItem().getState() == OpenClosedType.OPEN) { - isListening = false; - } - } - State itemState = consumer.getControlItem().getState(); - Date currentDate = new Date(); - Long timestamp = currentDate.getTime() / 1000; - consumer.getDeviceStatus().setTimestamp(timestamp); - consumer.getDeviceStatus().setEMSignalsAccepted(isListening); - if (!isConnected) { - consumer.getDeviceStatus().setStatus("Offline"); - logger.debug("STATE: Offline"); - } else { - if (itemState instanceof OnOffType) { - String state = (((OnOffType) itemState) == OnOffType.ON ? "On" : "Off"); - consumer.getDeviceStatus().setStatus(state); - logger.debug("Item: {} STATE: {}", consumer.getControlItem().getName(), state); - } else { - logger.error("Item {} from group {} is not from OnOffType type, type is: {} state is: {}", - consumer.getControlItem().getName(), consumer.getGroupItem().getName(), - consumer.getControlItem().getType(), consumer.getControlItem().getState()); - return false; - } - if (consumer.getEnergyItem() != null) { - itemState = consumer.getEnergyItem().getState(); - if ("On".equals(consumer.getDeviceStatus().getStatus())) { - if (itemState instanceof DecimalType) { - double state = (((DecimalType) itemState).doubleValue()); - consumer.getDeviceStatus().setAveragePower(state); - consumer.getDeviceStatus().setMinPower(state); - consumer.getDeviceStatus().setMaxPower(state); - consumer.getDeviceStatus().setAveragingInterval(60); - } else { - logger.error("Item is not from DecimalType type "); - return false; - } - } else { - if (itemState instanceof DecimalType) { - consumer.getDeviceStatus().setAveragePower(0.0); - consumer.getDeviceStatus().setMinPower(0.0); - consumer.getDeviceStatus().setMaxPower(0.0); - consumer.getDeviceStatus().setAveragingInterval(60); - } else { - logger.error("Item is not from DecimalType type "); - return false; - } - } - if (isPersistanceAvailible(consumer.getEnergyItem(), persistenceServices)) { - logger.debug("Persistence availible"); - consumer.getDeviceHistoryStatus().clear(); - for (int i = 0; i < 10; i++) { - Double sum = 0.0; - SEMPDeviceStatus historyStatus = new SEMPDeviceStatus(); - historicValues = getHistoryValue(consumer.getEnergyItem(), persistenceServices, - (timestamp - (i + 1) * consumer.getDeviceStatus().getAveragingInterval()) * 1000, - (timestamp - i * consumer.getDeviceStatus().getAveragingInterval()) * 1000); - if (historicValues == null || historicValues.size() <= 0) { - continue; - } - historyStatus.setAveragingInterval(consumer.getDeviceStatus().getAveragingInterval()); - historyStatus - .setTimestamp(timestamp - i * consumer.getDeviceStatus().getAveragingInterval()); - for (int j = 0; j < historicValues.size(); j++) { - logger.debug("SIZE: {} TIME: {}, VAL: {}", historicValues.size(), i, j); - sum += historicValues.get(j); - } - historyStatus.setMinPower(Collections.min(historicValues)); - historyStatus.setMaxPower(Collections.max(historicValues)); - historyStatus.setAveragePower(sum / historicValues.size()); - historyStatus.setStdDevPower(calculateStandardDeviation(historicValues)); - consumer.getDeviceHistoryStatus().add(historyStatus); - logger.debug("Avarage: {}: {}", i, sum / historicValues.size()); - } - consumer.hasHistory = true; - } else { - logger.debug("Persistence for group {} NOT availible", consumer.getGroupItem().getName()); - } - } else { - logger.debug("Energy item for group {} NOT availible", consumer.getGroupItem().getName()); - } - } - } - return true; - } - - public boolean deviceToItems(Map consumerMap, boolean onOffValue, String deviceID, - EventPublisher eventPublisher) { - String newState; - for (SEMPConsumer consumer : consumerMap.values()) { - if (!consumer.getIdentification().getDeviceId().equals(deviceID)) { - continue; - } - State itemState = consumer.getControlItem().getState(); - if (itemState instanceof OnOffType) { - if (onOffValue) { - newState = OnOffType.ON.toString(); - } else { - newState = OnOffType.OFF.toString(); - } - Command command = TypeParser.parseCommand(consumer.getControlItem().getAcceptedCommandTypes(), - newState); - eventPublisher.post(ItemEventFactory.createCommandEvent(consumer.getControlItem().getName(), command)); - } else { - logger.error("Item is not from OnOffType type "); - return false; - } - consumer.getDeviceStatus().setStatus(newState); - Date currentDate = new Date(); - Long timeStamp = currentDate.getTime() / 1000; - SEMPTimeFrame actTimeFrame = consumer.getCurrentTimeFrame(timeStamp); - if (actTimeFrame != null) { - if (OnOffType.OFF.toString().equals(newState)) { - if (!actTimeFrame.isTimestampActivatedSet()) { - return true; - } - Long currentRuntime = timeStamp - actTimeFrame.getTimestampActivated() - + actTimeFrame.getCurrentRuntime(); - if (currentRuntime < actTimeFrame.getMaxRunningTime()) { - actTimeFrame.setCurrentRuntime(currentRuntime.intValue()); - } else { - actTimeFrame.setCurrentRuntime(0); - actTimeFrame.setTimestampActivated(null); - } - } else { - actTimeFrame.setTimestampActivated(timeStamp); - } - } - } - return true; - } - - public boolean isPersistanceAvailible(Item item, Map persistenceServices) { - // Fallback to first persistenceService from list - if (!persistenceServices.entrySet().iterator().hasNext()) { - logger.debug("No Persistence service found."); - return false; - } - Date currentDate = new Date(); - long timeStamp = currentDate.getTime(); - - FilterCriteria filter = new FilterCriteria().setItemName(item.getName()).setEndDate(new Date(timeStamp)) - .setBeginDate(new Date(timeStamp - 60000)); - - Iterator> pit = persistenceServices.entrySet().iterator(); - QueryablePersistenceService persistenceService = pit.next().getValue(); - // Get the data from the persistence store - Iterable result = persistenceService.query(filter); - Iterator it = result.iterator(); - boolean forceStop = false; - while (!forceStop && !it.hasNext()) { - if (pit.hasNext()) { - persistenceService = pit.next().getValue(); - result = persistenceService.query(filter); - } else { - logger.debug("No persisted data found for item {} found, From: {}/{}, To: {}/{}", item, - timeStamp - 60000, new Date(timeStamp - 60000), timeStamp, new Date(timeStamp)); - // no persisted data found for this item in any of - // the available persistence services - forceStop = true; - return false; - } - } - return true; - } - - private List getHistoryValue(Item item, Map persistenceServices, - long begin, long end) { - logger.debug("Querying persistence for history of Item {}, from {} to {}", item.getName(), begin, end); - List values = new ArrayList(); - // Fallback to first persistenceService from list - if (!persistenceServices.entrySet().iterator().hasNext()) { - logger.debug("No Persistence service found."); - return null; - } - - FilterCriteria filter = new FilterCriteria().setItemName(item.getName()).setEndDate(new Date(end)) - .setBeginDate(new Date(begin)); - - Iterator> pit = persistenceServices.entrySet().iterator(); - QueryablePersistenceService persistenceService = pit.next().getValue(); - // Get the data from the persistence store - Iterable result = persistenceService.query(filter); - Iterator it = result.iterator(); - boolean forceStop = false; - while (!forceStop && !it.hasNext()) { - if (pit.hasNext()) { - persistenceService = pit.next().getValue(); - result = persistenceService.query(filter); - } else { - // no persisted data found for this item in any of - // the available persistence services - forceStop = true; - return null; - } - } - if (it.hasNext()) { - logger.debug("persisted data for item {} found in service {}", item.getName(), persistenceService.getId()); - } - - while (it.hasNext()) { - HistoricItem historicItem = it.next(); - logger.debug("Item: {}", historicItem.getState().toString()); - if (historicItem.getState().toString().isEmpty()) { - continue; - } - values.add(Double.valueOf(historicItem.getState().toString())); - } - return values; - } - - public Double calculateStandardDeviation(List numArray) { - Double sum = 0.0, standardDeviation = 0.0; - int length = numArray.size(); - for (Double num : numArray) { - sum += num; - } - Double mean = sum / length; - for (Double num : numArray) { - standardDeviation += Math.pow(num - mean, 2); - } - return Math.sqrt(standardDeviation / length); - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPServlet.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPServlet.java deleted file mode 100644 index 9582c9519cb87..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPServlet.java +++ /dev/null @@ -1,304 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -import java.io.IOException; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.util.Dictionary; -import java.util.Hashtable; -import java.util.Map; -import java.util.UUID; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.Response; - -import org.eclipse.smarthome.config.core.ConfigurableService; -import org.eclipse.smarthome.core.events.EventPublisher; -import org.eclipse.smarthome.core.items.ItemRegistry; -import org.eclipse.smarthome.core.persistence.PersistenceService; -import org.osgi.service.component.ComponentContext; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Deactivate; -import org.osgi.service.component.annotations.Modified; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.http.HttpService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Interface for SSDP/SEMP Informations - * - * @author Markus Eckhardt - Initial Contribution - * - */ -@SuppressWarnings("serial") -@Component(immediate = true, service = SEMPServlet.class, configurationPid = "org.openhab.semp", property = { - ConfigurableService.SERVICE_PROPERTY_DESCRIPTION_URI + "=io:semp", - ConfigurableService.SERVICE_PROPERTY_CATEGORY + "=io", - ConfigurableService.SERVICE_PROPERTY_LABEL + "=SEMP Service" }) -public class SEMPServlet extends HttpServlet { - private final Logger logger = LoggerFactory.getLogger(SEMPServlet.class); - private static final String CONFIG_DISCOVERY_IP = "discoveryIp"; - private static final String CONFIG_DISCOVERY_UUID = "discoveryUUID"; - private static final String CONFIG_DISCOVERY_HTTP_PORT = "discoveryHttpPort"; - private static final String PATH_SEMP = "/semp"; - private HttpService httpService; - private SEMPUpnpServer disco; - private int webPort; - private String uuid; - private boolean isConfigured = false; - private boolean isRunning = false; - - private SEMPCommandServlet commandServlet = new SEMPCommandServlet(); - - @Activate - protected void activate(Map config) { - modified(config); - if (!isRunning && isConfigured) { - startServlets(); - } - } - - @Modified - protected void modified(Map config) { - if (disco != null) { - disco.shutdown(); - disco = null; - } - if (isRunning) { - stopServlets(); - } - - Object obj = config.get(CONFIG_DISCOVERY_IP); - String ip = obj != null ? (String) obj : null; - obj = config.get(CONFIG_DISCOVERY_UUID); - if (obj == null) { - isConfigured = false; - return; - } - - UUID configUUID = null; - try { - configUUID = UUID.fromString((String) obj); - uuid = configUUID.toString(); - } catch (IllegalArgumentException e) { - logger.error("Wrong UUID: {} : {}", obj, e.toString()); - isConfigured = false; - return; - } - if (uuid == null) { - isConfigured = false; - return; - } - - obj = config.get(CONFIG_DISCOVERY_HTTP_PORT); - webPort = obj == null ? Integer.getInteger("org.osgi.service.http.port") : Integer.parseInt((String) obj); - disco = new SEMPUpnpServer("/uuid:" + uuid + "/description.xml", webPort, ip, uuid); - disco.start(); - isConfigured = true; - } - - private void startServlets() { - if (isRunning || !isConfigured) { - return; - } - try { - Dictionary servletParams = new Hashtable(); - httpService.registerServlet("/uuid:" + uuid, this, servletParams, httpService.createDefaultHttpContext()); - httpService.registerServlet(PATH_SEMP, commandServlet, servletParams, - httpService.createDefaultHttpContext()); - logger.info("Started SSDP/SEMP Info service at {} and {}.", "/uuid:" + uuid, PATH_SEMP); - isRunning = true; - } catch (Exception e) { - logger.error("Could not start SSDP/SEMP Info service: {}", e.getMessage(), e); - } - } - - private void stopServlets() { - try { - if (isRunning) { - httpService.unregister("/uuid:" + uuid); - httpService.unregister(PATH_SEMP); - } - isRunning = false; - } catch (IllegalArgumentException ignored) { - } - } - - @Deactivate - protected void deactivate(ComponentContext componentContext) { - stopServlets(); - if (disco != null) { - disco.shutdown(); - isConfigured = false; - } - } - - @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - commandServlet.setItemRegistry(itemRegistry); - } - - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - commandServlet.unsetItemRegistry(itemRegistry); - } - - @Reference - protected void setEventPublisher(EventPublisher eventPublisher) { - commandServlet.setEventPublisher(eventPublisher); - } - - protected void unsetEventPublisher(EventPublisher eventPublisher) { - commandServlet.unsetEventPublisher(eventPublisher); - } - - @Reference - protected void setHttpService(HttpService httpService) { - this.httpService = httpService; - } - - protected void unsetHttpService(HttpService httpService) { - this.httpService = null; - } - - @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) - public void addPersistenceService(PersistenceService service) { - commandServlet.addPersistenceService(service); - } - - public void removePersistenceService(PersistenceService service) { - commandServlet.removePersistenceService(service); - } - - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String path = req.getRequestURI(); - logger.debug("{}: {} {}", req.getRemoteAddr(), req.getMethod(), path); - - // handle UPnP device description request - if (("/uuid:" + uuid + "/description.xml").equals(path)) { - resp.setContentType("text/xml"); - apiDiscoveryXML(req, resp); - resp.setStatus(Response.Status.OK.getStatusCode()); - return; - } else if (("/uuid:" + uuid + "/presentation.html").equals(path)) { - resp.setContentType("text/html"); - apiDiscoveryHTML(req, resp); - resp.setStatus(Response.Status.OK.getStatusCode()); - return; - } else if (path.startsWith(PATH_SEMP)) { - // remove baseURI and remove trailing '/' if existing - String cmd = path.substring(PATH_SEMP.length()); - if (cmd.endsWith("/")) { - cmd = cmd.substring(0, cmd.length() - 2); - } - return; - } - } - - /** - * Returns a empty ("{}") JSON response - */ - public void emptyResponse(HttpServletRequest req, PrintWriter out) throws IOException { - out.write("{}"); - } - - /** - * Generates the XML Discovery document - * - * @return - * XML document - */ - public void apiDiscoveryXML(HttpServletRequest req, HttpServletResponse resp) throws IOException { - InetAddress address = disco.getAddress(); - if (address == null) { - return; - } - - StringBuilder xmlBuilder = new StringBuilder(); - xmlBuilder.append("\n"); - xmlBuilder.append("\n"); - xmlBuilder.append("\t\n"); - xmlBuilder.append("\t\t1\n"); - xmlBuilder.append("\t\t0\n"); - xmlBuilder.append("\t\n"); - xmlBuilder.append("\t\n"); - xmlBuilder.append("\t\turn:" + SEMPConstants.SEMP_DEVICE_CONFIG.urn + "\n"); - xmlBuilder.append("\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.friendlyName + "\n"); - xmlBuilder.append("\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.manufacturer + "\n"); - xmlBuilder.append( - "\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.manufacturerURL + "\n"); - xmlBuilder.append( - "\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.modelDescription + "\n"); - xmlBuilder.append("\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.modelName + "\n"); - xmlBuilder.append("\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.modelNumber + "\n"); - xmlBuilder.append("\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.modelURL + "\n"); - xmlBuilder.append("\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.serialNumber + "\n"); - xmlBuilder.append("\t\tuuid:" + uuid + "\n"); - xmlBuilder.append("\t\t\n"); - for (SEMPConstants.SSDPServiceConfig serviceConfig : SEMPConstants.SSDP_SERVICE_CONFIG_LIST) { - xmlBuilder.append("\t\t\t\n"); - xmlBuilder.append("\t\t\t\turn:" + serviceConfig.typeUrn + ":service:NULL:1\n"); - xmlBuilder.append("\t\t\t\turn:" + serviceConfig.idUrn + ":serviceId:NULL\n"); - xmlBuilder.append("\t\t\t\t" + serviceConfig.serviceDescriptorURL + "\n"); - xmlBuilder.append("\t\t\t\t" + serviceConfig.controlURL + "\n"); - xmlBuilder.append("\t\t\t\t" + serviceConfig.eventSubURL + "\n"); - xmlBuilder.append("\t\t\t\n"); - } - xmlBuilder.append("\t\t\n"); - xmlBuilder.append( - "\t\t" + SEMPConstants.SEMP_DEVICE_CONFIG.presentationURL + "\n"); - - for (String element : SEMPConstants.SEMP_DEVICE_CONFIG.additionalElements) { - element = element.replace("@IFACE_ADDR@", address.getHostAddress()); - xmlBuilder.append("\t\t" + element + "\n"); - } - xmlBuilder.append("\t\n"); - xmlBuilder.append("\n"); - - try (PrintWriter out = resp.getWriter()) { - out.write(xmlBuilder.toString()); - logger.debug("Dic: {}", xmlBuilder.toString()); - } - } - - /** - * Generates the HTML Discovery document - * - * @return - * HTML document - */ - public void apiDiscoveryHTML(HttpServletRequest req, HttpServletResponse resp) throws IOException { - InetAddress address = disco.getAddress(); - if (address == null) { - return; - } - - StringBuilder xmlBuilder = new StringBuilder(); - xmlBuilder.append("\n"); - xmlBuilder.append("\tSimpleEnergyManagementProtocol\n"); - xmlBuilder.append("\t

SEMP Gateway Demo

\n"); - xmlBuilder.append("\n"); - - try (PrintWriter out = resp.getWriter()) { - out.write(xmlBuilder.toString()); - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPTimeFrame.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPTimeFrame.java deleted file mode 100644 index 4883b7e89e32b..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPTimeFrame.java +++ /dev/null @@ -1,219 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -/** - * Time frame data object. - * - * @author Markus Eckhardt - Initial contribution - */ -public class SEMPTimeFrame { - /* - * Represents the earliest possible time the device can be switched on by the EM. - * The combination of EarliestStart and LatestEnd specifies the interval in which the requested runtime or energy - * has to be allocated by the EM. - */ - private Integer earliestStart; - - /* - * Represents the latest possible end time the requested minimum runtime (MinRunningTime) must be allocated to the - * device. This means at the given time the device operation must be finished. If a runtime was requested, the - * latest possible start of operation is LatestEnd-MinRunningTime. - * - * The combination of EarliestStart and LatestEnd specifies the interval in which the requested runtime or energy - * has to be allocated by the EM. - */ - private Integer latestEnd; - - /* - * Minimum running time within the timeframe in seconds. - * If MinRunningTime is 0, the operation of the device in this timeframe is optional. - * Defaults to 0 if MaxRunningTime is set. - */ - private Integer minRunningTime; - - /* - * Maximum running time within the timeframe in seconds. - * If MinRunningTime equals MaxRunningTime, all of the given runtime is required. - * If MinRunningTime is lower than MaxRunningTime, the amount of runtime given by MinRunningTime is required. The - * runtime difference between MinRunningTime and MaxRunningTime is optional. That means that the EM will only assign - * the optional - * runtime to the device if certain conditions like ecological constraints and/or price of energy are met. - * Defaults to MinRunningTime if MinRunningTime is set. - */ - private Integer maxRunningTime; - - /* - * Integer that provides the timestamp of the last activation. - */ - private Long timestampActivated; - - /* - * Integer that provides the runtime of this time frame - */ - private Integer currentRuntime; - - public SEMPTimeFrame() { - currentRuntime = 0; - } - - /* - * Setter for currentRuntime - */ - public void setCurrentRuntime(Integer currentRuntime) { - this.currentRuntime = currentRuntime; - } - - /* - * Getter for currentRuntime - */ - public Integer getCurrentRuntime() { - return currentRuntime; - } - - /* - * Checks if field currentRuntime is set - */ - public boolean isCurrentRuntimeSet() { - if (currentRuntime == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for timestampActivated - */ - public void setTimestampActivated(Long statusTimestamp) { - this.timestampActivated = statusTimestamp; - } - - /* - * Getter for timestampActivated - */ - public Long getTimestampActivated() { - return timestampActivated; - } - - /* - * Checks if field timestampActivated is set - */ - public boolean isTimestampActivatedSet() { - if (timestampActivated == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for earliestStart - */ - public void setEarliestStart(Integer earliestStart) { - this.earliestStart = earliestStart; - } - - /* - * Getter for earliestStart - */ - public Integer getEarliestStart() { - return earliestStart; - } - - /* - * Checks if field earliestStart is set - */ - public boolean isEarliestStartSet() { - if (earliestStart == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for latestEnd - */ - public void setLatestEnd(Integer latestEnd) { - this.latestEnd = latestEnd; - } - - /* - * Getter for latestEnd - */ - public Integer getLatestEnd() { - return latestEnd; - } - - /* - * Checks if field latestEnd is set - */ - public boolean isLatestEndSet() { - if (latestEnd == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for minRunningTime - */ - public void setMinRunningTime(Integer minRunningTime) { - this.minRunningTime = minRunningTime; - } - - /* - * Getter for minRunningTime - */ - public Integer getMinRunningTime() { - return minRunningTime; - } - - /* - * Checks if field minRunningTime is set - */ - public boolean isMinRunningTimeSet() { - if (minRunningTime == null) { - return false; - } else { - return true; - } - } - - /* - * Setter for maxRunningTime - */ - public void setMaxRunningTime(Integer maxRunningTime) { - this.maxRunningTime = maxRunningTime; - } - - /* - * Getter for maxRunningTime - */ - public Integer getMaxRunningTime() { - return maxRunningTime; - } - - /* - * Checks if field maxRunningTime is set - */ - public boolean isMaxRunningTimeSet() { - if (maxRunningTime == null) { - return false; - } else { - return true; - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPUpnpServer.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPUpnpServer.java deleted file mode 100644 index d1a6ff37cb5f8..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPUpnpServer.java +++ /dev/null @@ -1,302 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.MulticastSocket; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.openhab.io.semp.internal.SEMPConstants.SSDPDiscoveryType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * SEMP upnp Gateway - * - * @author Markus Eckhardt - Initial Contribution - * - */ -public class SEMPUpnpServer extends Thread { - private final Logger logger = LoggerFactory.getLogger(SEMPUpnpServer.class); - - // jUPNP shares port 1900, but since this is multicast, we can also bind to it - private static final int UPNP_PORT_RECV = 1900; - private static final String MULTI_ADDR = "239.255.255.250"; - private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); - private boolean running; - private String discoPath; - private InetAddress address; - private String discoveryIp; - private String discoveryUUID; - private int webPort; - private String discoString = "HTTP/1.1 200 OK\r\n" + "HOST: %s:%d\r\n" + "EXT:\r\n" - + "CACHE-CONTROL: max-age=1800\r\n" + "LOCATION: %s\r\n" - + "SERVER: Linux/2.6.32 UPnP/1.0 SMA SSDP Server/1.0.0\r\n"; - - public SEMPUpnpServer(String discoPath, int webPort, String discoveryIP, String discoveryUUID) { - this.running = true; - this.discoPath = discoPath; - this.webPort = webPort; - this.discoveryIp = discoveryIP; - this.discoveryUUID = discoveryUUID; - - logger.debug("Starting send and receive executor"); - NotifyRunnable notifyRunnable = new NotifyRunnable(); - executor.scheduleWithFixedDelay(notifyRunnable, 15, SEMPConstants.SSDP_VALIDITY_PERIOD / 6, TimeUnit.SECONDS); - - } - - public void shutdown() { - this.running = false; - executor.shutdown(); - sendNotify(false); - } - - @Override - public void run() { - MulticastSocket recvSocket = null; - byte[] buf = new byte[1000]; - DatagramPacket recv = new DatagramPacket(buf, buf.length); - while (running) { - try { - if (discoveryIp != null && discoveryIp.trim().length() > 0) { - address = InetAddress.getByName(discoveryIp); - } else { - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); - while (interfaces.hasMoreElements()) { - NetworkInterface ni = interfaces.nextElement(); - Enumeration addresses = ni.getInetAddresses(); - while (addresses.hasMoreElements()) { - InetAddress addr = addresses.nextElement(); - if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) { - address = addr; - logger.debug("Network address: {}", address); - break; - } - } - } - } - InetSocketAddress socketAddr = new InetSocketAddress(MULTI_ADDR, UPNP_PORT_RECV); - recvSocket = new MulticastSocket(UPNP_PORT_RECV); - recvSocket.joinGroup(socketAddr, NetworkInterface.getByInetAddress(address)); - while (running) { - logger.debug("UPNP is running"); - recvSocket.receive(recv); - if (recv.getLength() > 0) { - String data = new String(recv.getData()); - logger.debug("Got SSDP Discovery packet from {}:{}", recv.getAddress().getHostAddress(), - recv.getPort()); - logger.debug("Data: {}", data); - if (data.startsWith("M-SEARCH * HTTP/1.1") && data.contains("ssdp:discover")) { - String[] dataLines = StringUtils.split(data, "\r\n"); - String searchTarget = null; - for (int i = 1; i < dataLines.length; ++i) { - if (dataLines[i].startsWith("ST:")) { - searchTarget = dataLines[i].substring(3).trim(); - logger.debug("searchTarget: {}", searchTarget); - } - } - if (searchTarget == null) { - return; - } - String header = String.format(discoString, MULTI_ADDR, UPNP_PORT_RECV, - "http://" + address.getHostAddress().toString() + ":" + webPort + discoPath); - String response; - if ("ssdp:all".equals(searchTarget)) { - response = header + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_ROOTDEVICE, true) - + "\r\n"; - sendResponseDatagramPacket(response, recv); - - response = header + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_DEVICEID_TYPE, true) - + "\r\n"; - sendResponseDatagramPacket(response, recv); - - response = header + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_DEVICE_TYPE, true) - + "\r\n"; - sendResponseDatagramPacket(response, recv); - - for (SEMPConstants.SSDPServiceConfig serviceConfig : SEMPConstants.SSDP_SERVICE_CONFIG_LIST) { - response = header + getDiscoveryServiceNtUsn(serviceConfig, true) + "\r\n"; - sendResponseDatagramPacket(response, recv); - } - } else if ("upnp:rootdevice".equals(searchTarget)) { - response = header + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_ROOTDEVICE, true) - + "\r\n"; - sendResponseDatagramPacket(response, recv); - } else if (("uuid:" + discoveryUUID).equals(searchTarget)) { - response = header + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_DEVICEID_TYPE, true) - + "\r\n"; - sendResponseDatagramPacket(response, recv); - } else if (("urn:" + SEMPConstants.SEMP_DEVICE_CONFIG.urn).equals(searchTarget)) { - response = header + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_DEVICE_TYPE, true) - + "\r\n"; - sendResponseDatagramPacket(response, recv); - } else { - for (SEMPConstants.SSDPServiceConfig serviceConfig : SEMPConstants.SSDP_SERVICE_CONFIG_LIST) { - if (("urn:" + serviceConfig.typeUrn).equals(searchTarget)) { - response = header + getDiscoveryServiceNtUsn(serviceConfig, true) + "\r\n"; - sendResponseDatagramPacket(response, recv); - } - } - } - } - } - } - - } catch (SocketException e) { - logger.error("Socket error with UPNP server", e); - } catch (IOException e) { - logger.error("IO Error with UPNP server", e); - } finally { - IOUtils.closeQuietly(recvSocket); - if (running) { - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - } - } - } - } - } - - public InetAddress getAddress() { - return address; - } - - private String getDiscoveryNtUsn(SSDPDiscoveryType type, boolean useSearchTarget) { - String targetPrefix = (useSearchTarget ? "ST" : "NT"); - - switch (type) { - case SSDP_DT_ROOTDEVICE: - targetPrefix += ": upnp:rootdevice\r\n" + "USN: uuid:" + discoveryUUID + "::upnp:rootdevice\r\n"; - break; - case SSDP_DT_DEVICE_TYPE: - targetPrefix += ": urn:" + SEMPConstants.SEMP_DEVICE_CONFIG.urn + "\r\n" + "USN: uuid:" + discoveryUUID - + "::urn:" + SEMPConstants.SEMP_DEVICE_CONFIG.urn + "\r\n"; - break; - case SSDP_DT_DEVICEID_TYPE: - targetPrefix += ": uuid:" + discoveryUUID + "\r\n" + "USN: uuid:" + discoveryUUID + "\r\n"; - break; - default: - return ""; - } - return targetPrefix; - } - - private String getDiscoveryServiceNtUsn(SEMPConstants.SSDPServiceConfig svc, boolean useSearchTarget) { - String targetPrefix = (useSearchTarget ? "ST" : "NT"); - return targetPrefix + ": urn:" + svc.typeUrn + "\r\n" + "USN: uuid:" + discoveryUUID + "::urn:" + svc.typeUrn - + "\r\n"; - } - - private void sendResponseDatagramPacket(String msg, DatagramPacket recv) { - DatagramSocket sendSocket = null; - try { - sendSocket = new DatagramSocket(); - DatagramPacket response = new DatagramPacket(msg.getBytes(), msg.length(), recv.getAddress(), - recv.getPort()); - logger.debug("Sending to {} : {}", recv.getAddress().getHostAddress(), msg); - sendSocket.send(response); - } catch (SocketException e) { - logger.error("Socket error with UPNP server", e); - } catch (IOException e) { - logger.debug("Could not send UPNP response: {}", e.getMessage()); - } finally { - IOUtils.closeQuietly(sendSocket); - if (running) { - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - } - } - } - } - - void sendNotify(boolean alive) { - String msg; - DatagramPacket dgPacket; - StringBuilder notifyBuilder = new StringBuilder(); - MulticastSocket mcSocket = null; - InetAddress iGgroup = null; - try { - iGgroup = InetAddress.getByName(SEMPConstants.SSDP_MCAST_IP); - mcSocket = new MulticastSocket(SEMPConstants.SSDP_MCAST_PORT); - mcSocket.joinGroup(iGgroup); - - notifyBuilder.append("NOTIFY * HTTP/1.1\r\n"); - notifyBuilder.append("HOST: " + SEMPConstants.SSDP_MCAST_IP + ":" - + String.valueOf(SEMPConstants.SSDP_MCAST_PORT) + "\r\n"); - if (alive) { - notifyBuilder.append("CACHE-CONTROL: max-age = " + SEMPConstants.SSDP_VALIDITY_PERIOD + "\r\n"); - notifyBuilder.append("SERVER: " + SEMPConstants.SSDP_SERVER_TYPE + "\r\n"); - notifyBuilder.append("NTS: ssdp:alive\r\n"); - notifyBuilder.append( - "LOCATION: http://" + address.getHostAddress().toString() + ":" + webPort + discoPath + "\r\n"); - } else { - notifyBuilder.append("NTS: ssdp:byebye\r\n"); - } - - msg = notifyBuilder + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_ROOTDEVICE, false) + "\r\n"; - dgPacket = new DatagramPacket(msg.getBytes(), msg.length(), iGgroup, SEMPConstants.SSDP_MCAST_PORT); - mcSocket.send(dgPacket); - logger.debug("Send Notify: {}", msg); - - msg = notifyBuilder + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_DEVICEID_TYPE, false) + "\r\n"; - dgPacket = new DatagramPacket(msg.getBytes(), msg.length(), iGgroup, SEMPConstants.SSDP_MCAST_PORT); - mcSocket.send(dgPacket); - logger.debug("Send Notify: {}", msg); - - msg = notifyBuilder + getDiscoveryNtUsn(SSDPDiscoveryType.SSDP_DT_DEVICE_TYPE, false) + "\r\n"; - dgPacket = new DatagramPacket(msg.getBytes(), msg.length(), iGgroup, SEMPConstants.SSDP_MCAST_PORT); - mcSocket.send(dgPacket); - logger.debug("Send Notify: {}", msg); - - for (SEMPConstants.SSDPServiceConfig serviceConfig : SEMPConstants.SSDP_SERVICE_CONFIG_LIST) { - msg = notifyBuilder + getDiscoveryServiceNtUsn(serviceConfig, true) + "\r\n"; - dgPacket = new DatagramPacket(msg.getBytes(), msg.length(), iGgroup, SEMPConstants.SSDP_MCAST_PORT); - mcSocket.send(dgPacket); - logger.debug("Send Notify: {}", msg); - } - - mcSocket.leaveGroup(iGgroup); - } catch (IOException e) { - logger.error("Notify error: {}", e.getMessage()); - } - } - - private class NotifyRunnable implements Runnable { - - public NotifyRunnable() { - } - - @Override - public void run() { - logger.debug("NotifyRunnable"); - sendNotify(true); - } - - } - -} diff --git a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPXmlTools.java b/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPXmlTools.java deleted file mode 100644 index d0c7278ccb48c..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/java/org/openhab/io/semp/internal/SEMPXmlTools.java +++ /dev/null @@ -1,396 +0,0 @@ -/** - * Copyright (c) 2010-2019 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.io.semp.internal; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.StringWriter; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.TextStyle; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.openhab.io.semp.internal.SEMPConstants.SEMPMessageType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -/** - * XML Tools für device communication - * - * @author Markus Eckhardt - Initial Contribution - * - */ -public class SEMPXmlTools { - private final Logger logger = LoggerFactory.getLogger(SEMPXmlTools.class); - - public String createXMLMessage(List typeList, Map consumerMap, - String deviceID) { - DocumentBuilderFactory icFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder icBuilder = null; - try { - icBuilder = icFactory.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - logger.error("{}", e); - return null; - } - org.w3c.dom.Document doc = icBuilder.newDocument(); - Element mainRootElement = doc.createElementNS("http://www.sma.de/communication/schema/SEMP/v1", "Device2EM"); - doc.appendChild(mainRootElement); - for (SEMPMessageType type : typeList) { - switch (type) { - case MSG_DEVICE_INFO: - for (SEMPConsumer consumer : consumerMap.values()) { - if (!consumer.getIdentification().getDeviceId().equals(deviceID) && !"".equals(deviceID)) { - continue; - } - Element deviceInfo = doc.createElement("DeviceInfo"); - Element indentification = doc.createElement("Identification"); - if (consumer.getIdentification().isDeviceIdSet()) { - indentification.appendChild( - generateTextNode(doc, "DeviceId", consumer.getIdentification().getDeviceId())); - } - if (consumer.getIdentification().isDeviceNameSet()) { - indentification.appendChild( - generateTextNode(doc, "DeviceName", consumer.getIdentification().getDeviceName())); - } - if (consumer.getIdentification().isDeviceTypeSet()) { - indentification.appendChild( - generateTextNode(doc, "DeviceType", consumer.getIdentification().getDeviceType())); - } - if (consumer.getIdentification().isDeviceSerialSet()) { - indentification.appendChild(generateTextNode(doc, "DeviceSerial", - consumer.getIdentification().getDeviceSerial())); - } - if (consumer.getIdentification().isDeviceVendorSet()) { - indentification.appendChild(generateTextNode(doc, "DeviceVendor", - consumer.getIdentification().getDeviceVendor())); - } - deviceInfo.appendChild(indentification); - Element characteristics = doc.createElement("Characteristics"); - if (consumer.getCharacteristics().isMaxPowerConsumptionSet()) { - characteristics.appendChild(generateTextNode(doc, "MaxPowerConsumption", - String.valueOf(consumer.getCharacteristics().getMaxPowerConsumption()))); - } - if (consumer.getCharacteristics().isMinOnTimeSet()) { - characteristics.appendChild(generateTextNode(doc, "MinOnTime", - String.valueOf(consumer.getCharacteristics().getMinOnTime()))); - } - if (consumer.getCharacteristics().isMinOffTimeSet()) { - characteristics.appendChild(generateTextNode(doc, "MinOffTime", - String.valueOf(consumer.getCharacteristics().getMinOffTime()))); - } - deviceInfo.appendChild(characteristics); - Element capabilities = doc.createElement("Capabilities"); - if (consumer.getCapabilities().isMethodSet()) { - Element node = doc.createElement("CurrentPower"); - node.appendChild(generateTextNode(doc, "Method", consumer.getCapabilities().getMethod())); - capabilities.appendChild(node); - } - if (consumer.getCapabilities().isAbsoluteTimestampsSet()) { - Element node = doc.createElement("Timestamps"); - node.appendChild(generateTextNode(doc, "AbsoluteTimestamps", - String.valueOf(consumer.getCapabilities().getAbsoluteTimestamps()))); - capabilities.appendChild(node); - } - if (consumer.getCapabilities().isInterruptionsAllowedSet()) { - Element node = doc.createElement("Interruptions"); - node.appendChild(generateTextNode(doc, "InterruptionsAllowed", - String.valueOf(consumer.getCapabilities().getInterruptionsAllowed()))); - capabilities.appendChild(node); - } - if (consumer.getCapabilities().isOptionalEnergySet()) { - Element node = doc.createElement("Requests"); - node.appendChild(generateTextNode(doc, "OptionalEnergy", - String.valueOf(consumer.getCapabilities().getOptionalEnergy()))); - capabilities.appendChild(node); - } - deviceInfo.appendChild(capabilities); - mainRootElement.appendChild(deviceInfo); - } - break; - case MSG_DEVICE_STATUS: - for (SEMPConsumer consumer : consumerMap.values()) { - if (!consumer.getIdentification().getDeviceId().equals(deviceID) && !"".equals(deviceID)) { - continue; - } - Element deviceStatus = doc.createElement("DeviceStatus"); - if (consumer.getIdentification().isDeviceIdSet()) { - deviceStatus.appendChild( - generateTextNode(doc, "DeviceId", consumer.getIdentification().getDeviceId())); - } - if (consumer.getDeviceStatus().isEMSignalsAcceptedSet()) { - deviceStatus.appendChild(generateTextNode(doc, "EMSignalsAccepted", - String.valueOf(consumer.getDeviceStatus().getEMSignalsAccepted()))); - } - if (consumer.getDeviceStatus().isStatusSet()) { - deviceStatus.appendChild( - generateTextNode(doc, "Status", consumer.getDeviceStatus().getStatus())); - } - Element powerConsumption = doc.createElement("PowerConsumption"); - if (!consumer.hasHistory) { - Element powerInfo = doc.createElement("PowerInfo"); - if (consumer.getDeviceStatus().isAveragePowerSet()) { - powerInfo.appendChild(generateTextNode(doc, "AveragePower", - String.valueOf(Math.round(consumer.getDeviceStatus().getAveragePower())))); - } - if (consumer.getDeviceStatus().isTimestampSet()) { - powerInfo.appendChild(generateTextNode(doc, "Timestamp", - String.valueOf(consumer.getDeviceStatus().getTimestamp()))); - } - if (consumer.getDeviceStatus().isAveragingIntervalSet()) { - powerInfo.appendChild(generateTextNode(doc, "AveragingInterval", - String.valueOf(consumer.getDeviceStatus().getAveragingInterval()))); - } - powerConsumption.appendChild(powerInfo); - } else { - for (int i = 0; i < consumer.getDeviceHistoryStatus().size(); i++) { - Element powerInfo = doc.createElement("PowerInfo"); - if (consumer.getDeviceHistoryStatus().get(i).isAveragePowerSet()) { - powerInfo.appendChild(generateTextNode(doc, "AveragePower", String.valueOf( - Math.round(consumer.getDeviceHistoryStatus().get(i).getAveragePower())))); - } - if (consumer.getDeviceHistoryStatus().get(i).isMaxPowerSet()) { - powerInfo.appendChild(generateTextNode(doc, "MaxPower", String.valueOf( - Math.round(consumer.getDeviceHistoryStatus().get(i).getMaxPower())))); - } - if (consumer.getDeviceHistoryStatus().get(i).isMinPowerSet()) { - powerInfo.appendChild(generateTextNode(doc, "MinPower", String.valueOf( - Math.round(consumer.getDeviceHistoryStatus().get(i).getMinPower())))); - } - if (consumer.getDeviceHistoryStatus().get(i).isStdDevPowerSet()) { - powerInfo.appendChild(generateTextNode(doc, "StdDevPower", - String.valueOf(consumer.getDeviceHistoryStatus().get(i).getStdDevPower()))); - } - if (consumer.getDeviceHistoryStatus().get(i).isTimestampSet()) { - powerInfo.appendChild(generateTextNode(doc, "Timestamp", - String.valueOf(consumer.getDeviceHistoryStatus().get(i).getTimestamp()))); - } - if (consumer.getDeviceHistoryStatus().get(i).isAveragingIntervalSet()) { - powerInfo.appendChild(generateTextNode(doc, "AveragingInterval", String - .valueOf(consumer.getDeviceHistoryStatus().get(i).getAveragingInterval()))); - } - powerConsumption.appendChild(powerInfo); - } - } - deviceStatus.appendChild(powerConsumption); - mainRootElement.appendChild(deviceStatus); - } - break; - case MSG_TIMEFRAME: - for (SEMPConsumer consumer : consumerMap.values()) { - if (!consumer.getIdentification().getDeviceId().equals(deviceID) && !"".equals(deviceID)) { - continue; - } - Date currentDate = new Date(); - long unixActTime = currentDate.getTime() / 1000; - if (!arePlaningRequestsAvailible(consumer, unixActTime)) { - mainRootElement.appendChild(doc.createComment("PlanningRequest element omitted")); - } else { - Element planningRequest = doc.createElement("PlanningRequest"); - for (int i = 0; i < consumer.getTimeFrames().size(); i++) { - if (isRequestInPast(consumer, unixActTime, i)) { - continue; - } - Element timeFrame = doc.createElement("Timeframe"); - if (consumer.getIdentification().isDeviceIdSet()) { - timeFrame.appendChild(generateTextNode(doc, "DeviceId", - consumer.getIdentification().getDeviceId())); - } - if (consumer.getTimeFrames().get(i).isEarliestStartSet()) { - timeFrame.appendChild(generateTextNode(doc, "EarliestStart", - calculateEarliestStart(consumer, i, unixActTime))); - } - if (consumer.getTimeFrames().get(i).isLatestEndSet()) { - timeFrame.appendChild(generateTextNode(doc, "LatestEnd", - calculateLatestEnd(consumer, i, unixActTime))); - } - if (consumer.getTimeFrames().get(i).isMaxRunningTimeSet()) { - timeFrame.appendChild(generateTextNode(doc, "MaxRunningTime", - calculateMaxRunningTime(consumer, i, unixActTime))); - } - if (consumer.getTimeFrames().get(i).isMinRunningTimeSet()) { - timeFrame.appendChild(generateTextNode(doc, "MinRunningTime", - calculateMinRunningTime(consumer, i, unixActTime))); - } - planningRequest.appendChild(timeFrame); - } - mainRootElement.appendChild(planningRequest); - } - } - break; - default: - break; - } - } - - // output DOM XML to console - Transformer transformer = null; - try { - transformer = TransformerFactory.newInstance().newTransformer(); - } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) { - logger.error("{}", e); - return null; - } - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "0"); - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - transformer.setOutputProperty(OutputKeys.VERSION, "1.0"); - - DOMSource source = new DOMSource(doc); - StringWriter writer = new StringWriter(); - try { - transformer.transform(source, new StreamResult(writer)); - } catch (TransformerException e) { - logger.error("{}", e); - return null; - } - return writer.toString(); - } - - private Element generateTextNode(org.w3c.dom.Document doc, String nodeName, String nodeValue) { - Element node = doc.createElement(nodeName); - node.appendChild(doc.createTextNode(nodeValue)); - return node; - } - - public String getXMLValue(ByteArrayInputStream xmlStream, String xPath) { - String value = null; - org.w3c.dom.Document doc; - DocumentBuilderFactory icFactory = DocumentBuilderFactory.newInstance(); - DocumentBuilder icBuilder = null; - try {// - icBuilder = icFactory.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - logger.error("{}", e); - return null; - } - try { - doc = icBuilder.parse(xmlStream); - } catch (SAXException | IOException e) { - logger.error("{}", e); - return null; - } - XPathFactory factory = XPathFactory.newInstance(); - XPath xpath = factory.newXPath(); - try { - value = (String) xpath.evaluate(xPath, doc, XPathConstants.STRING); - } catch (XPathExpressionException e) { - logger.error("{}", e); - return null; - } - return value; - } - - private String calculateEarliestStart(SEMPConsumer consumer, int index, long unixActTime) { - LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); - long unixDayTime = startOfToday.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(Instant.now())); - long earliestStart = consumer.getTimeFrames().get(index).getEarliestStart() + unixDayTime; - if (earliestStart > unixActTime) { - return String.valueOf(earliestStart); - } else { - return String.valueOf(unixActTime); - } - } - - private String calculateLatestEnd(SEMPConsumer consumer, int index, long unixActTime) { - LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); - long unixDayTime = startOfToday.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(Instant.now())); - return String.valueOf(consumer.getTimeFrames().get(index).getLatestEnd() + unixDayTime); - } - - private String calculateMaxRunningTime(SEMPConsumer consumer, int index, long unixActTime) { - SEMPTimeFrame actTimeFrame = consumer.getCurrentTimeFrame(unixActTime); - if (actTimeFrame == null || !actTimeFrame.isTimestampActivatedSet() - || index != consumer.getTimeFrames().indexOf(actTimeFrame)) { - return String.valueOf(consumer.getTimeFrames().get(index).getMaxRunningTime()); - } - long remainingMaxRunningTime = consumer.getTimeFrames().get(index).getMaxRunningTime() - + (actTimeFrame.getTimestampActivated() - unixActTime) - actTimeFrame.getCurrentRuntime(); - if (remainingMaxRunningTime > 0) { - return String.valueOf(remainingMaxRunningTime); - } else { - return String.valueOf("0"); - } - } - - private String calculateMinRunningTime(SEMPConsumer consumer, int index, long unixActTime) { - SEMPTimeFrame actTimeFrame = consumer.getCurrentTimeFrame(unixActTime); - if (actTimeFrame == null || !actTimeFrame.isTimestampActivatedSet() - || index != consumer.getTimeFrames().indexOf(actTimeFrame)) { - return String.valueOf(consumer.getTimeFrames().get(index).getMinRunningTime()); - } - long remainingMinRunningTime = consumer.getTimeFrames().get(index).getMinRunningTime() - + (actTimeFrame.getTimestampActivated() - unixActTime) - actTimeFrame.getCurrentRuntime(); - if (remainingMinRunningTime > 0) { - return String.valueOf(remainingMinRunningTime); - } else { - return String.valueOf("0"); - } - } - - private boolean arePlaningRequestsAvailible(SEMPConsumer consumer, long unixActTime) { - if (consumer.getTimeFrames().isEmpty()) { - return false; - } - LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); - String dOW = startOfToday.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.US); - if (!consumer.getDaysOfTheWeek().isEmpty() && !consumer.getDaysOfTheWeek().contains(dOW)) { - return false; - } - long unixDayTime = startOfToday.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(Instant.now())); - long latestEnd = consumer.getTimeFrames().get(consumer.getTimeFrames().size() - 1).getLatestEnd() + unixDayTime; - if (latestEnd > unixActTime) { - return true; - } else { - return false; - } - } - - private boolean isRequestInPast(SEMPConsumer consumer, long unixActTime, int index) { - if (consumer.getTimeFrames().isEmpty()) { - return false; - } - LocalDateTime startOfToday = LocalDate.now().atStartOfDay(); - long unixDayTime = startOfToday.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(Instant.now())); - long latestEnd = consumer.getTimeFrames().get(index).getLatestEnd() + unixDayTime; - if (latestEnd > unixActTime) { - return false; - } else { - return true; - } - } -} diff --git a/bundles/org.openhab.io.semp/src/main/resources/ESH-INF/config/config.xml b/bundles/org.openhab.io.semp/src/main/resources/ESH-INF/config/config.xml deleted file mode 100644 index a21715782f288..0000000000000 --- a/bundles/org.openhab.io.semp/src/main/resources/ESH-INF/config/config.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - An UUID (Universal Unique Identifier) is a 128-bit number used to uniquely identify some object or entity on the Internet. It is possible to use a random generated UUID. - - - - - If your host has multiple IP addresses you may specify the IP you would like to advertise in the UPNP discovery process. You may safely leave this empty on most systems. - - - - - Some SEMP applications require a different port (80) then what openHAB runs on by default (8080). This option will only advertise a different port then what we are listening on. Useful if you have an iptables rule redirect traffic from this port to the openHAB port. - true - - - - diff --git a/bundles/pom.xml b/bundles/pom.xml index 485ab94110768..84d9b259b5048 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -25,7 +25,6 @@ org.openhab.io.javasound org.openhab.io.neeo org.openhab.io.openhabcloud - org.openhab.io.semp org.openhab.io.transport.modbus org.openhab.io.mqttembeddedbroker org.openhab.io.webaudio