From c4cb9ff4580d4b77609e89c9a6f7686b60434d11 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Fri, 15 Mar 2024 00:07:52 +0100 Subject: [PATCH] Added Tibber plugin --- .../hal/plugin/tibber/TibberController.java | 183 ++++++++++++++++++ .../se/hal/plugin/tibber/TibberDevice.java | 28 +++ .../tibber/device/ElectricityCostSensor.java | 64 ++++++ .../tibber/device/ElectricityPriceSensor.java | 65 +++++++ .../tibber/device/PowerConsumptionSensor.java | 61 ++++++ .../src/se/hal/plugin/tibber/plugin.json | 12 ++ 6 files changed, 413 insertions(+) create mode 100644 plugins/hal-tibber/src/se/hal/plugin/tibber/TibberController.java create mode 100644 plugins/hal-tibber/src/se/hal/plugin/tibber/TibberDevice.java create mode 100644 plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityCostSensor.java create mode 100644 plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityPriceSensor.java create mode 100644 plugins/hal-tibber/src/se/hal/plugin/tibber/device/PowerConsumptionSensor.java create mode 100644 plugins/hal-tibber/src/se/hal/plugin/tibber/plugin.json diff --git a/plugins/hal-tibber/src/se/hal/plugin/tibber/TibberController.java b/plugins/hal-tibber/src/se/hal/plugin/tibber/TibberController.java new file mode 100644 index 00000000..cc9067d4 --- /dev/null +++ b/plugins/hal-tibber/src/se/hal/plugin/tibber/TibberController.java @@ -0,0 +1,183 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.tibber; + +import se.hal.HalContext; +import se.hal.HalServer; +import se.hal.intf.*; +import zutil.ObjectUtil; +import zutil.log.LogUtil; +import zutil.net.http.HttpClient; +import zutil.net.http.HttpHeader; +import zutil.parser.DataNode; +import zutil.parser.json.JSONParser; +import zutil.ui.UserMessageManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + + +public class TibberController implements HalSensorController, Runnable, HalDaemon, HalAutostartController { + private static final Logger logger = LogUtil.getLogger(); + + private static final String CONFIG_TIBBER_TOKEN = "hal_tibber.token"; + + private static final String TIBBER_API_ENDPOINT = "https://api.tibber.com/v1-beta/gql"; + private static final int POLL_TIME = 60*60; // poll every 1h defined in sec + + private List registeredDevices = new ArrayList<>(); + private List deviceListeners = new CopyOnWriteArrayList<>(); + private ScheduledExecutorService executor; + + + public TibberController() {} + + @Override + public boolean isAvailable() { + return HalContext.containsProperty(CONFIG_TIBBER_TOKEN); + } + + @Override + public void initialize() { + HalServer.registerDaemon(this); + } + + @Override + public void initiate(ScheduledExecutorService executor) { + this.executor = executor; + executor.scheduleAtFixedRate(this, 10, POLL_TIME, TimeUnit.SECONDS); + } + + @Override + public synchronized void run() { + if (!isAvailable()) { + logger.warning("Controller not available yet."); + return; + } + + try { + logger.fine("Querying Tibber API for new data."); + + HttpClient client = new HttpClient(HttpClient.HttpRequestType.POST); + client.setURL(TIBBER_API_ENDPOINT); + client.setHeader("Authorization", "Bearer " + HalContext.getStringProperty(CONFIG_TIBBER_TOKEN)); + client.setContent("application/json"); + String requestQuery = "{ " + + "\"query\": \"{" + + "viewer {" + + "homes {" + + "consumption(resolution: HOURLY, last: 1) {" + + "nodes {" + + "from " + + "to " + + "cost " + // Total cost + "unitPrice " + // Cost per Kwh + "unitPriceVAT " + // Cost per Kwh with taxes + "consumption " + // Total consumption + "consumptionUnit " + // Should be Kwh + "}" + + "}" + +// "currentSubscription {" + +// "priceInfo {" + +// "current {" + +// "total " + +// "energy " + +// "tax " + +// "startsAt " + +// "}" + +// "}" + +// "}" + + "}" + + "}" + + "}\"" + + "}"; + client.setContent(requestQuery); + logger.finest("Request: " + requestQuery); + + HttpHeader header = client.send(); + JSONParser parser = new JSONParser(header.getInputStream()); + DataNode json = parser.read(); + logger.finest("Response: " + json); + + if (header.getResponseStatusCode() != 200) { + logger.severe("There was a error fetching data from tibber: StatusCode=" + header.getResponseStatusCode() + ", Response=" + header.getResponseStatusString()); + HalContext.getUserMessageManager().add(new UserMessageManager.UserMessage( + UserMessageManager.MessageLevel.ERROR, + "Tibber API error.", + "There was a error fetching data from tibber: StatusCode=" + header.getResponseStatusCode() + ", Response=" + header.getResponseStatusString(), + UserMessageManager.MessageTTL.DISMISSED)); + return; + } + + if (!ObjectUtil.isEmpty(json.get("error"))) { + logger.severe("There was a error fetching data from tibber: " + json.getString("error")); + HalContext.getUserMessageManager().add(new UserMessageManager.UserMessage( + UserMessageManager.MessageLevel.ERROR, + "Tibber API error.", + "There was a error fetching data from tibber: " + json.getString("error"), + UserMessageManager.MessageTTL.DISMISSED)); + return; + } + + DataNode data = json.get("data").get("viewer").get("homes").get(0).get("consumption").get("nodes").get(0); + + } catch (Exception e) { + logger.log(Level.SEVERE, "Tibber API querying failed.", e); + } + } + + @Override + public synchronized void register(HalDeviceConfig deviceConfig) { + if (deviceConfig instanceof TibberDevice) + registeredDevices.add((TibberDevice) deviceConfig); + } + + @Override + public synchronized void deregister(HalDeviceConfig deviceConfig) { + registeredDevices.remove(deviceConfig); + } + + @Override + public int size() { + return registeredDevices.size(); + } + + @Override + public void addListener(HalDeviceReportListener listener) { + if (!deviceListeners.contains(listener)) + deviceListeners.add(listener); + } + + @Override + public synchronized void close() { + registeredDevices = new ArrayList<>(); + + } +} diff --git a/plugins/hal-tibber/src/se/hal/plugin/tibber/TibberDevice.java b/plugins/hal-tibber/src/se/hal/plugin/tibber/TibberDevice.java new file mode 100644 index 00000000..b05ea79f --- /dev/null +++ b/plugins/hal-tibber/src/se/hal/plugin/tibber/TibberDevice.java @@ -0,0 +1,28 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.tibber; + +public interface TibberDevice { +} \ No newline at end of file diff --git a/plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityCostSensor.java b/plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityCostSensor.java new file mode 100644 index 00000000..9a2c8381 --- /dev/null +++ b/plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityCostSensor.java @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.tibber.device; + +import se.hal.intf.HalSensorConfig; +import se.hal.intf.HalSensorController; +import se.hal.intf.HalSensorData; +import se.hal.plugin.tibber.TibberController; +import se.hal.struct.devicedata.HumiditySensorData; + +/** + * A sensor that calculate current electricity bil + */ +public class ElectricityCostSensor implements HalSensorConfig { + + + + @Override + public long getDataInterval() { + return 60*60*1000; // 1 h + } + + @Override + public AggregationMethod getAggregationMethod() { + return AggregationMethod.SUM; + } + + @Override + public Class getDeviceControllerClass() { + return TibberController.class; + } + + @Override + public Class getDeviceDataClass() { + return CostSensorData.class; + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } +} diff --git a/plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityPriceSensor.java b/plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityPriceSensor.java new file mode 100644 index 00000000..25ff2acd --- /dev/null +++ b/plugins/hal-tibber/src/se/hal/plugin/tibber/device/ElectricityPriceSensor.java @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.tibber.device; + +import se.hal.intf.HalDeviceData; +import se.hal.intf.HalSensorConfig; +import se.hal.intf.HalSensorController; +import se.hal.intf.HalSensorData; +import se.hal.struct.devicedata.HumiditySensorData; +import se.hal.plugin.tibber.TibberController; + +/** + * A sensor that shows the price of electricity at a specific time + */ +public class ElectricityPriceSensor implements HalSensorConfig { + + + + @Override + public long getDataInterval() { + return 60*60*1000; // 1 h + } + + @Override + public AggregationMethod getAggregationMethod() { + return AggregationMethod.AVERAGE; + } + + @Override + public Class getDeviceControllerClass() { + return TibberController.class; + } + + @Override + public Class getDeviceDataClass() { + return PriceSensorData.class; + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } +} diff --git a/plugins/hal-tibber/src/se/hal/plugin/tibber/device/PowerConsumptionSensor.java b/plugins/hal-tibber/src/se/hal/plugin/tibber/device/PowerConsumptionSensor.java new file mode 100644 index 00000000..ed5dbca8 --- /dev/null +++ b/plugins/hal-tibber/src/se/hal/plugin/tibber/device/PowerConsumptionSensor.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.tibber.device; + +import se.hal.intf.HalSensorConfig; +import se.hal.intf.HalSensorController; +import se.hal.intf.HalSensorData; +import se.hal.struct.devicedata.TemperatureSensorData; +import se.hal.plugin.tibber.TibberController; + + +public class PowerConsumptionSensor implements HalSensorConfig { + + + @Override + public long getDataInterval() { + return 60*60 * 1000; // 1 min + } + + @Override + public AggregationMethod getAggregationMethod() { + return AggregationMethod.AVERAGE; + } + + @Override + public Class getDeviceControllerClass() { + return TibberController.class; + } + + @Override + public Class getDeviceDataClass() { + return TemperatureSensorData.class; + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } +} diff --git a/plugins/hal-tibber/src/se/hal/plugin/tibber/plugin.json b/plugins/hal-tibber/src/se/hal/plugin/tibber/plugin.json new file mode 100644 index 00000000..bb3021c3 --- /dev/null +++ b/plugins/hal-tibber/src/se/hal/plugin/tibber/plugin.json @@ -0,0 +1,12 @@ +{ + "version": 0.1, + "name": "Hal-Tibber", + "description": "Plugin that connects to the Tibber API.", + "interfaces": [ + {"se.hal.intf.HalAutostartController": "se.hal.plugin.tibber.TibberController"}, + + {"se.hal.intf.HalSensorConfig": "se.hal.plugin.tibber.device.ElectricityCostSensor"}, + {"se.hal.intf.HalSensorConfig": "se.hal.plugin.tibber.device.ElectricityPriceSensor"}, + {"se.hal.intf.HalSensorConfig": "se.hal.plugin.tibber.device.PowerConsumptionSensor"} + ] +} \ No newline at end of file