From 21a672acf417c60d8928a8edd67aa0b1d1a75c8f Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Thu, 23 Oct 2025 23:21:29 +0200 Subject: [PATCH] Implementation of EcoSens Cloud API --- .../struct/devicedata/RadonSensorData.java | 65 ++++++ plugins/hal-vendor-ecosense/build.gradle | 28 +++ .../ecosense/EcoSenseCloudAPIClient.java | 212 ++++++++++++++++++ .../vendor/ecosense/EcoSenseController.java | 125 +++++++++++ .../ecosense/device/EccoCubeRadonSensor.java | 69 ++++++ .../se/hal/plugin/vendor/ecosense/plugin.json | 10 + .../ecosense/EcoSenseCloudAPIClientTest.java | 43 ++++ 7 files changed, 552 insertions(+) create mode 100644 hal-core/src/se/hal/struct/devicedata/RadonSensorData.java create mode 100644 plugins/hal-vendor-ecosense/build.gradle create mode 100644 plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClient.java create mode 100644 plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseController.java create mode 100644 plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/device/EccoCubeRadonSensor.java create mode 100644 plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/plugin.json create mode 100644 plugins/hal-vendor-ecosense/test/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClientTest.java diff --git a/hal-core/src/se/hal/struct/devicedata/RadonSensorData.java b/hal-core/src/se/hal/struct/devicedata/RadonSensorData.java new file mode 100644 index 00000000..a44b41c6 --- /dev/null +++ b/hal-core/src/se/hal/struct/devicedata/RadonSensorData.java @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 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.struct.devicedata; + +import se.hal.intf.HalSensorData; + +public class RadonSensorData extends HalSensorData { + + private double radon; + + + public RadonSensorData(){} + public RadonSensorData(double radon, long timestamp){ + this.radon = radon; + super.setTimestamp(timestamp); + } + + + @Override + public String toString(){ + return radon + " Bq/m³"; + } + + // ---------------------------------------- + // Storage methods + // ---------------------------------------- + + /** + * @return radon measurement in Bq/m3 + */ + @Override + public double getData() { + return radon; + } + + /** + * @param radon the radon measurement in Bq/m3 + */ + @Override + public void setData(double radon) { + this.radon = radon; + } +} diff --git a/plugins/hal-vendor-ecosense/build.gradle b/plugins/hal-vendor-ecosense/build.gradle new file mode 100644 index 00000000..0f6c5a03 --- /dev/null +++ b/plugins/hal-vendor-ecosense/build.gradle @@ -0,0 +1,28 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 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. + */ + +dependencies { + implementation project(':hal-core') + implementation 'software.amazon.awssdk:cognitoidentityprovider:2.35.10' +} diff --git a/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClient.java b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClient.java new file mode 100644 index 00000000..7c9f85ea --- /dev/null +++ b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClient.java @@ -0,0 +1,212 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 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.vendor.ecosense; + +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient; +import software.amazon.awssdk.services.cognitoidentityprovider.model.AuthFlowType; +import software.amazon.awssdk.services.cognitoidentityprovider.model.InitiateAuthRequest; +import software.amazon.awssdk.services.cognitoidentityprovider.model.InitiateAuthResponse; +import zutil.ObjectUtil; +import zutil.log.LogUtil; +import zutil.net.http.HttpURL; +import zutil.net.ws.WSInterface; +import zutil.net.ws.rest.RESTClient; +import zutil.parser.DataNode; +import zutil.parser.json.JSONWriter; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * API Client class that connects to EcoSense cloud API. + * + * Reference: https://github.com/rwestergren/hass-ecosense-radon + */ +public class EcoSenseCloudAPIClient { + private static final Logger logger = LogUtil.getLogger(); + + private static final String USER_POOL_ID = "us-west-2_vB73oNa7f"; + private static final String CLIENT_ID = "1dk9ul54cdo42lt6e9u1oa9g1d"; + private static final String USER_POOL_REGION = "us-west-2"; + private static final String API_URL = "https://api.cloud.ecosense.io/api"; + + private static SimpleDateFormat DATE_PARSER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); //2025-10-22T14:09:29.691533 + + private String username; + private String password; + /** The authenticated Amazon Cognito ID token. */ + private String idToken; + + public EcoSenseCloudAPIClient(String username, String password) { + this.username = username; + this.password = password; + } + + public void authenticate() { + CognitoIdentityProviderClient cognitoClient = CognitoIdentityProviderClient.builder() + .region(Region.of(USER_POOL_REGION)) + .credentialsProvider(AnonymousCredentialsProvider.create()) + .build(); + + Map authParameters = new HashMap<>(); + authParameters.put("USERNAME", username); + authParameters.put("PASSWORD", password); + + InitiateAuthRequest authRequest = InitiateAuthRequest.builder() + .authFlow(AuthFlowType.USER_PASSWORD_AUTH) + .authParameters(authParameters) + .clientId(CLIENT_ID) + .build(); + + InitiateAuthResponse authResult = cognitoClient.initiateAuth(authRequest); + this.idToken = authResult.authenticationResult().idToken(); + cognitoClient.close(); + } + + public EcoSenseDevice getDevices() { + try { + if (ObjectUtil.isEmpty(idToken)) { + authenticate(); + } + + RESTClient client = new RESTClient(WSInterface.RequestType.GET, new HttpURL(API_URL + "/v1/device")); + client.setHeader("Authorization", "Bearer " + idToken); + client.setParameter("email", username); + DataNode rootNode = client.send(); + + for (DataNode deviceNode : rootNode) { + EcoSenseDevice ecoSenseDevice = new EcoSenseDevice(); + ecoSenseDevice.pollingPeriod = deviceNode.getInt("polling_period"); + ecoSenseDevice.ledStatus = deviceNode.getString("led_status"); + ecoSenseDevice.subscription = deviceNode.getString("subscription"); + ecoSenseDevice.radonLevel = deviceNode.getInt("radon_level"); + ecoSenseDevice.deactivated = deviceNode.getString("deactivated"); + ecoSenseDevice.ledValue = deviceNode.getInt("led_value"); + ecoSenseDevice.deviceName = deviceNode.getString("device_name"); + ecoSenseDevice.geoCdnt = deviceNode.getString("geo_cdnt"); + ecoSenseDevice.alarmStatus = deviceNode.getString("alarm_status"); + ecoSenseDevice.geoHash = deviceNode.getString("geohash"); + ecoSenseDevice.subsStatus = deviceNode.getString("subs_status"); + ecoSenseDevice.email = deviceNode.getString("email"); + ecoSenseDevice.externalIp = deviceNode.getString("external_ip"); + ecoSenseDevice.dStatus = deviceNode.getInt("d_status"); + ecoSenseDevice.dType = deviceNode.getInt("d_type"); + ecoSenseDevice.radonDou = deviceNode.getInt("radon_dou"); + ecoSenseDevice.alarmValue = deviceNode.getInt("alarm_value"); + ecoSenseDevice.mvMode = deviceNode.getInt("mv_mode"); + ecoSenseDevice.deviceLocationZipcode = deviceNode.get("device_location").getString("zipcode"); + ecoSenseDevice.deviceLocationCountry = deviceNode.get("device_location").getString("country"); + ecoSenseDevice.deviceLocationCity = deviceNode.get("device_location").getString("city"); + ecoSenseDevice.deviceLocationStreet = deviceNode.get("device_location").getString("street"); + ecoSenseDevice.deviceLocationCountryCode = deviceNode.get("device_location").getString("countryCode"); + ecoSenseDevice.deviceLocationCounty = deviceNode.get("device_location").getString("county"); + ecoSenseDevice.deviceLocationDetail = deviceNode.get("device_location").getString("detail"); + ecoSenseDevice.deviceLocationState = deviceNode.get("device_location").getString("state"); + ecoSenseDevice.serialNumber = deviceNode.getString("serial_number"); + ecoSenseDevice.timeZone = deviceNode.getString("time_zone"); + ecoSenseDevice.devicePlacementLocationFloor = deviceNode.get("device_placement").getString("location_floor"); + ecoSenseDevice.devicePlacementLocationMitigationInstalled = deviceNode.get("device_placement").getString("mitigation_installed"); + ecoSenseDevice.devicePlacementLocationLocationType = deviceNode.get("device_placement").getString("location_type"); + ecoSenseDevice.devicePlacementLocationRoomType = deviceNode.get("device_placement").getString("room_type"); + ecoSenseDevice.pushNotification = deviceNode.getString("push_notification"); + ecoSenseDevice.unit = deviceNode.getInt("unit"); + ecoSenseDevice.registrationDate = deviceNode.getString("registration_date"); + ecoSenseDevice.pTime = deviceNode.getInt("p_time"); + ecoSenseDevice.cFactor = deviceNode.getDouble("c_factor"); + ecoSenseDevice.guest = deviceNode.getInt("guest"); + ecoSenseDevice.fwVersion = deviceNode.getString("fw_version"); + ecoSenseDevice.wifiName = deviceNode.getString("wifi_name"); + + try { + ecoSenseDevice.lastRadonUpdateTime = DATE_PARSER.parse(deviceNode.getString("last_radon_update_time")).getTime(); + ecoSenseDevice.lastUpdateTime = DATE_PARSER.parse(deviceNode.getString("last_update_time")).getTime(); + } catch (Exception e) { + logger.log(Level.WARNING, "Was unable to parse timestamp from EcoSense API.", e); + } + + return ecoSenseDevice; + } + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } catch (IOException e) { + idToken = null; + throw new RuntimeException(e); + } + + return null; + } + + public class EcoSenseDevice { + public int pollingPeriod; + public String ledStatus; + public String subscription; + public int radonLevel; + public String deactivated; + public int ledValue; + public String deviceName; + public String geoCdnt; + public String alarmStatus; + public String geoHash; + public String subsStatus; + public String email; + public String externalIp; + public int dStatus; + public int dType; + public int radonDou; + public int alarmValue; + public int mvMode; + public String deviceLocationZipcode; + public String deviceLocationCountry; + public String deviceLocationCity; + public String deviceLocationStreet; + public String deviceLocationCountryCode; + public String deviceLocationCounty; + public String deviceLocationDetail; + public String deviceLocationState; + public String serialNumber; + public String timeZone; + public String devicePlacementLocationFloor; + public String devicePlacementLocationMitigationInstalled; + public String devicePlacementLocationLocationType; + public String devicePlacementLocationRoomType; + public String pushNotification; + public long lastRadonUpdateTime; + public long lastUpdateTime; + public int unit; + public String registrationDate; + public int pTime; + public double cFactor; + public int guest; + public String fwVersion; + public String wifiName; + } +} \ No newline at end of file diff --git a/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseController.java b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseController.java new file mode 100644 index 00000000..f1337a06 --- /dev/null +++ b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/EcoSenseController.java @@ -0,0 +1,125 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 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.vendor.ecosense; + +import se.hal.HalContext; +import se.hal.HalServer; +import se.hal.intf.*; +import se.hal.plugin.vendor.ecosense.device.EccoCubeRadonSensor; +import se.hal.struct.devicedata.RadonSensorData; +import zutil.ObjectUtil; +import zutil.log.LogUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class EcoSenseController implements HalSensorController, Runnable, HalDaemon, HalAutostartController { + private static final Logger logger = LogUtil.getLogger(); + + private static final String CONFIG_ECOSENSE_USERNAME = "hal_vendor_ecosense.username"; + private static final String CONFIG_ECOSENSE_PASSWORD = "hal_vendor_ecosense.password"; + private static final int POLL_TIME = 10*60; // poll every 10 min defined in sec + + private EcoSenseCloudAPIClient ecoSenseClient; + private List registeredDevices = new ArrayList<>(); + private HalDeviceReportListener deviceReportListener; + private ScheduledFuture threadSchedule; + + + @Override + public boolean isAvailable() { + return HalContext.containsProperty(CONFIG_ECOSENSE_USERNAME) && + HalContext.containsProperty(CONFIG_ECOSENSE_PASSWORD); + } + + @Override + public void initialize() throws Exception { + ecoSenseClient = new EcoSenseCloudAPIClient( + HalContext.getStringProperty(CONFIG_ECOSENSE_USERNAME), + HalContext.getStringProperty(CONFIG_ECOSENSE_PASSWORD) + ); + HalServer.registerDaemon(this); + } + + @Override + public void initiate(ScheduledExecutorService executor) { + threadSchedule = executor.scheduleAtFixedRate(this, 10, POLL_TIME, TimeUnit.SECONDS); + } + + @Override + public void run() { + try { + if (!ObjectUtil.isEmpty(ecoSenseClient)) { + EcoSenseCloudAPIClient.EcoSenseDevice apiResponse = ecoSenseClient.getDevices(); + if (apiResponse == null) { + logger.warning("Received empty response from EcoSense API."); + return; + } + + EccoCubeRadonSensor radonSensor = new EccoCubeRadonSensor(); + radonSensor.setSerialNumber(apiResponse.serialNumber); + + RadonSensorData radonSensorData = new RadonSensorData(apiResponse.radonLevel, apiResponse.lastRadonUpdateTime); + + if (deviceReportListener != null) { + deviceReportListener.reportReceived(radonSensor, radonSensorData); + } + } + } catch (Exception e) { + logger.log(Level.SEVERE, "Failed to poll EcoSense API.", e); + } + } + + @Override + public void register(HalDeviceConfig deviceConfig) { + registeredDevices.add(deviceConfig); + } + + @Override + public void deregister(HalDeviceConfig deviceConfig) { + registeredDevices.remove(deviceConfig); + } + + @Override + public int size() { + return registeredDevices.size(); + } + + @Override + public void addListener(HalDeviceReportListener listener) { + this.deviceReportListener = listener; + } + + @Override + public void close() { + registeredDevices.clear(); + threadSchedule.cancel(false); + } +} diff --git a/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/device/EccoCubeRadonSensor.java b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/device/EccoCubeRadonSensor.java new file mode 100644 index 00000000..4c0d302a --- /dev/null +++ b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/device/EccoCubeRadonSensor.java @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024-2025 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.vendor.ecosense.device; + +import se.hal.intf.HalSensorConfig; +import se.hal.intf.HalSensorController; +import se.hal.intf.HalSensorData; +import se.hal.plugin.vendor.ecosense.EcoSenseController; +import se.hal.struct.devicedata.RadonSensorData; + +/** + * A sensor that calculate current radon level + */ +public class EccoCubeRadonSensor implements HalSensorConfig { + + private String serialNumber; + + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } + + @Override + public long getDataInterval() { + return 10*60*1000; // 10 min + } + + @Override + public AggregationMethod getAggregationMethod() { + return AggregationMethod.AVERAGE; + } + + @Override + public Class getDeviceControllerClass() { + return EcoSenseController.class; + } + + @Override + public Class getDeviceDataClass() { + return RadonSensorData.class; + } + + @Override + public boolean equals(Object obj) { + return false; + } +} diff --git a/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/plugin.json b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/plugin.json new file mode 100644 index 00000000..71801055 --- /dev/null +++ b/plugins/hal-vendor-ecosense/src/se/hal/plugin/vendor/ecosense/plugin.json @@ -0,0 +1,10 @@ +{ + "version": 0.1, + "name": "Hal-Vendor-EcoSense", + "description": "Plugin that connects to EcoSense Cloud API.", + "interfaces": [ + {"se.hal.intf.HalAutostartController": "se.hal.plugin.vendor.ecosense.EcoSenseController"}, + + {"se.hal.intf.HalSensorConfig": "se.hal.plugin.vendor.ecosense.device.EccoCubeRadonSensor"} + ] +} \ No newline at end of file diff --git a/plugins/hal-vendor-ecosense/test/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClientTest.java b/plugins/hal-vendor-ecosense/test/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClientTest.java new file mode 100644 index 00000000..efc390ef --- /dev/null +++ b/plugins/hal-vendor-ecosense/test/se/hal/plugin/vendor/ecosense/EcoSenseCloudAPIClientTest.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 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.vendor.ecosense; + +import zutil.io.MultiPrintStream; + +import static org.junit.Assert.*; + +public class EcoSenseCloudAPIClientTest { + public static void main(String[] args) { + if (args.length != 2) { + System.out.println("ERROR: Please provide username and password as startup parameters."); + System.exit(1); + } + + EcoSenseCloudAPIClient client = new EcoSenseCloudAPIClient(args[0], args[1]); + client.authenticate(); + client.getDevices(); + } + +} \ No newline at end of file