mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[electroluxappliance] Initial contribution (#17663)
* First version Signed-off-by: Jan Gustafsson <jannegpriv@gmail.com>
This commit is contained in:
parent
5929ef821a
commit
da97e57aac
@ -96,6 +96,7 @@
|
||||
/bundles/org.openhab.binding.ecovacs/ @maniac103
|
||||
/bundles/org.openhab.binding.ecowatt/ @lolodomo
|
||||
/bundles/org.openhab.binding.ekey/ @hmerk
|
||||
/bundles/org.openhab.binding.electroluxappliance/ @jannegpriv
|
||||
/bundles/org.openhab.binding.elerotransmitterstick/ @vbier
|
||||
/bundles/org.openhab.binding.elroconnects/ @mherwege
|
||||
/bundles/org.openhab.binding.emotiva/ @espenaf
|
||||
|
@ -471,6 +471,11 @@
|
||||
<artifactId>org.openhab.binding.ekey</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.electroluxappliance</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.elerotransmitterstick</artifactId>
|
||||
|
13
bundles/org.openhab.binding.electroluxappliance/NOTICE
Normal file
13
bundles/org.openhab.binding.electroluxappliance/NOTICE
Normal file
@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
122
bundles/org.openhab.binding.electroluxappliance/README.md
Normal file
122
bundles/org.openhab.binding.electroluxappliance/README.md
Normal file
@ -0,0 +1,122 @@
|
||||
# Electrolux Appliance Binding
|
||||
|
||||
This is a binding for Electrolux appliances.
|
||||
|
||||
## Supported Things
|
||||
|
||||
This binding supports the following thing types:
|
||||
|
||||
- api: Bridge - Implements the Electrolux Group API that is used to communicate with the different appliances
|
||||
- air-purifier: The Electrolux Air Purifier
|
||||
- washing-machine: The Electrolux Washing Machine
|
||||
|
||||
## Discovery
|
||||
|
||||
After the configuration of the `api` bridge, your Electrolux appliances will be automatically discovered and placed as a thing in the inbox.
|
||||
|
||||
### Configuration Options
|
||||
|
||||
Only the bridge requires manual configuration.
|
||||
The Electrolux appliance things can be added by hand, or you can let the discovery mechanism automatically find them.
|
||||
|
||||
#### `api` Bridge
|
||||
|
||||
| Parameter | Description | Type | Default | Required |
|
||||
|--------------|--------------------------------------------------------|--------|----------|----------|
|
||||
| apiKey | Your created API key on developer.electrolux.one | String | NA | yes |
|
||||
| refreshToken | Your created refresh token on developer.electrolux.one | String | NA | yes |
|
||||
| refresh | Specifies the refresh interval in second | Number | 600 | yes |
|
||||
|
||||
#### `air-purifier` Electrolux Air Purifier
|
||||
|
||||
| Parameter | Description | Type | Default | Required |
|
||||
|--------------|--------------------------------------------------------------------------|--------|----------|----------|
|
||||
| serialNumber | Serial Number of your Electrolux appliance found in the Electrolux app | Number | NA | yes |
|
||||
|
||||
#### `washing-machine` Electrolux Washing Machine
|
||||
|
||||
| Parameter | Description | Type | Default | Required |
|
||||
|--------------|--------------------------------------------------------------------------|--------|----------|----------|
|
||||
| serialNumber | Serial Number of your Electrolux appliance found in the Electrolux app | Number | NA | yes |
|
||||
|
||||
## Channels
|
||||
|
||||
### Electrolux Air Purifier
|
||||
|
||||
The following channels are supported:
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------------------|-----------------------|--------------------------------------------------------------------------------|
|
||||
| temperature | Number:Temperature | This channel reports the current temperature. |
|
||||
| humidity | Number:Dimensionless | This channel reports the current humidity in percentage. |
|
||||
| tvoc | Number:Dimensionless | This channel reports the total Volatile Organic Compounds in ppb. |
|
||||
| pm1 | Number:Density | This channel reports the Particulate Matter 1 in microgram/m3. |
|
||||
| pm2_5 | Number:Density | This channel reports the Particulate Matter 2.5 in microgram/m3. |
|
||||
| pm10 | Number:Density | This channel reports the Particulate Matter 10 in microgram/m3. |
|
||||
| co2 | Number:Dimensionless | This channel reports the CO2 level in ppm. |
|
||||
| fan-speed | Number | This channel sets and reports the current fan speed (1-9). |
|
||||
| filter-life | Number:Dimensionless | This channel reports the remaining filter life in %. |
|
||||
| ionizer | Switch | This channel sets and reports the status of the Ionizer function (On/Off). |
|
||||
| door-state | Contact | This channel reports the status of the door (Opened/Closed). |
|
||||
| work-mode | String | This channel sets and reports the current work mode (Auto, Manual, PowerOff.) |
|
||||
| ui-light | Switch | This channel sets and reports the status of the UI Light function (On/Off). |
|
||||
| safety-lock | Switch | This channel sets and reports the status of the Safety Lock function. |
|
||||
| status | String | This channel is used to fetch latest status from the API. |
|
||||
|
||||
### Electrolux Washing Machine
|
||||
|
||||
The following channels are supported:
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|------------------------------|-----------------------|--------------------------------------------------------------------------------|
|
||||
| door-state | Contact | This channel reports the status of the door (Opened/Closed). |
|
||||
| door-lock | Contact | This channel reports the status of the door lock. |
|
||||
| time-to-start | Number:Time | This channel reports the remaining time for a delayed start washing program. |
|
||||
| time-to-end | Number:Time | This channel reports the remaining time to the end for a washing program. |
|
||||
| cycle-phase | String | This channel reports the washing cycle phase. |
|
||||
| analog-temperature | String | This channel reports the washing temperature. |
|
||||
| steam-value | String | This channel reports the washing steam value. |
|
||||
| programs-order | String | This channel reports the washing program. |
|
||||
| analog-spin-speed | String | This channel reports the washing spin speed. |
|
||||
| appliance-state | String | This channel reports the appliance state. |
|
||||
| appliance-mode | String | This channel reports the appliance mode. |
|
||||
| appliance-total-working-time | Number:Time | This channel reports the total working time for the washing machine. |
|
||||
| appliance-ui-sw-version | String | This channel reports the appliance UI SW version. |
|
||||
| optisense-result | String | This channel reports the optisense result. |
|
||||
| detergent-extradosage | String | This channel reports the detergent extra dosage. |
|
||||
| softener-extradosage | String | This channel reports the softener extra dosage. |
|
||||
| water-usage | Number:Volume | This channel reports the water usage in litres. |
|
||||
| total-wash-cycles-count | Number | This channel reports the total number of washing cycles. |
|
||||
| status | String | This channel is used to fetch latest status from the API. |
|
||||
|
||||
## Full Example
|
||||
|
||||
### `demo.things` Example
|
||||
|
||||
```java
|
||||
// Bridge configuration
|
||||
Bridge electroluxappliance:api:myAPI "Electrolux Group API" [apiKey="12345678", refreshToken="12345678", refresh="300"] {
|
||||
Thing air-purifier myair-purifier "Electrolux Pure A9" [ serialNummber="123456789" ]
|
||||
}
|
||||
```
|
||||
|
||||
## `demo.items` Example
|
||||
|
||||
```java
|
||||
// CO2
|
||||
Number:Dimensionless electroluxapplianceCO2 "Electrolux Air CO2 [%d ppm]" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:co2"}
|
||||
// Temperature
|
||||
Number:Temperature electroluxapplianceTemperature "Electrolux Air Temperature" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:temperature"}
|
||||
// Door status
|
||||
Contact electroluxapplianceDoor "Electrolux Air Door Status" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:doorOpen"}
|
||||
// Work mode
|
||||
String electroluxapplianceWorkModeSetting "electroluxappliance Work Mode Setting" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:workMode"}
|
||||
// Fan speed
|
||||
Number electroluxapplianceFanSpeed "Electrolux Air Fan Speed Setting" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:fanSpeed"}
|
||||
// UI Light
|
||||
Switch electroluxapplianceUILight "Electrolux Air UI Light Setting" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:uiLight"}
|
||||
// Ionizer
|
||||
Switch electroluxapplianceIonizer "Electrolux Air Ionizer Setting" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:ionizer"}
|
||||
// Safety Lock
|
||||
Switch electroluxapplianceSafetyLock "Electrolux Air Safety Lock Setting" {channel="electroluxappliance:air-purifier:myAPI:myair-purifier:safetyLock"}
|
||||
```
|
17
bundles/org.openhab.binding.electroluxappliance/pom.xml
Normal file
17
bundles/org.openhab.binding.electroluxappliance/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>4.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.electroluxappliance</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Electrolux Appliance Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.electroluxappliance-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-electroluxappliance" description="Electrolux Appliance Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.electroluxappliance/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxApplianceBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxApplianceBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "electroluxappliance";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_ELECTROLUX_AIR_PURIFIER = new ThingTypeUID(BINDING_ID, "air-purifier");
|
||||
public static final ThingTypeUID THING_TYPE_ELECTROLUX_WASHING_MACHINE = new ThingTypeUID(BINDING_ID,
|
||||
"washing-machine");
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "api");
|
||||
|
||||
// List of all common Channel ids
|
||||
public static final String CHANNEL_DOOR_STATE = "door-state";
|
||||
|
||||
// List of all Channel ids for Air Purifers
|
||||
public static final String CHANNEL_STATUS = "status";
|
||||
public static final String CHANNEL_TEMPERATURE = "temperature";
|
||||
public static final String CHANNEL_HUMIDITY = "humidity";
|
||||
public static final String CHANNEL_TVOC = "tvoc";
|
||||
public static final String CHANNEL_PM1 = "pm1";
|
||||
public static final String CHANNEL_PM25 = "pm2_5";
|
||||
public static final String CHANNEL_PM10 = "pm10";
|
||||
public static final String CHANNEL_CO2 = "co2";
|
||||
public static final String CHANNEL_FILTER_LIFE = "filter-life";
|
||||
public static final String CHANNEL_FAN_SPEED = "fan-speed";
|
||||
public static final String CHANNEL_WORK_MODE = "work-mode";
|
||||
public static final String CHANNEL_IONIZER = "ionizer";
|
||||
public static final String CHANNEL_UI_LIGHT = "ui-light";
|
||||
public static final String CHANNEL_SAFETY_LOCK = "safety-lock";
|
||||
|
||||
// List of all Channel ids for Washing Machines
|
||||
public static final String CHANNEL_DOOR_LOCK = "door-lock";
|
||||
public static final String CHANNEL_TIME_TO_START = "time-to-start";
|
||||
public static final String CHANNEL_TIME_TO_END = "time-to-end";
|
||||
public static final String CHANNEL_APPLIANCE_UI_SW_VERSION = "appliance-ui-sw-version";
|
||||
public static final String CHANNEL_APPLIANCE_TOTAL_WORKING_TIME = "appliance-total-working-time";
|
||||
public static final String CHANNEL_APPLIANCE_STATE = "appliance-state";
|
||||
public static final String CHANNEL_APPLIANCE_MODE = "appliance-mode";
|
||||
public static final String CHANNEL_OPTISENSE_RESULT = "optisense-result";
|
||||
public static final String CHANNEL_DETERGENT_EXTRA_DOSAGE = "detergent-extradosage";
|
||||
public static final String CHANNEL_SOFTENER_EXTRA_DOSAGE = "softener-extradosage";
|
||||
public static final String CHANNEL_WATER_USAGE = "water-usage";
|
||||
public static final String CHANNEL_CYCLE_PHASE = "cycle-phase";
|
||||
public static final String CHANNEL_TOTAL_WASH_CYCLES_COUNT = "total-wash-cycles-count";
|
||||
public static final String CHANNEL_ANALOG_TEMPERATURE = "analog-temperature";
|
||||
public static final String CHANNEL_ANALOG_SPIN_SPEED = "analog-spin-speed";
|
||||
public static final String CHANNEL_STEAM_VALUE = "steam-value";
|
||||
public static final String CHANNEL_PROGRAMS_ORDER = "programs-order";
|
||||
|
||||
// List of all Properties ids
|
||||
public static final String PROPERTY_BRAND = "brand";
|
||||
public static final String PROPERTY_COLOUR = "colour";
|
||||
public static final String PROPERTY_MODEL = "model";
|
||||
public static final String PROPERTY_DEVICE = "device";
|
||||
public static final String PROPERTY_FW_VERSION = "fwVersion";
|
||||
public static final String PROPERTY_SERIAL_NUMBER = "serialNumber";
|
||||
public static final String PROPERTY_WORKMODE = "workmode";
|
||||
|
||||
// List of all Commands for Air Purifiers
|
||||
public static final String COMMAND_WORKMODE_POWEROFF = "PowerOff";
|
||||
public static final String COMMAND_WORKMODE_AUTO = "Auto";
|
||||
public static final String COMMAND_WORKMODE_MANUAL = "Manual";
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BRIDGE,
|
||||
THING_TYPE_ELECTROLUX_AIR_PURIFIER, THING_TYPE_ELECTROLUX_WASHING_MACHINE);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxApplianceBridgeConfiguration} class contains fields mapping bridge configuration parameters.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxApplianceBridgeConfiguration {
|
||||
public String apiKey = "";
|
||||
public String refreshToken = "";
|
||||
public int refresh = 600;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxApplianceConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxApplianceConfiguration {
|
||||
public static final String SERIAL_NUMBER_LABEL = "serialNumber";
|
||||
|
||||
private String serialNumber = "";
|
||||
|
||||
public String getSerialNumber() {
|
||||
return serialNumber;
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* {@link ElectroluxApplianceException} is used when there is exception communicating with Electrolux Delta API.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxApplianceException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 2543564118231301159L;
|
||||
|
||||
public ElectroluxApplianceException(Exception source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public ElectroluxApplianceException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getMessage() {
|
||||
Throwable throwable = getCause();
|
||||
if (throwable != null) {
|
||||
String localMessage = throwable.getMessage();
|
||||
if (localMessage != null) {
|
||||
return localMessage;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -0,0 +1,322 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.api;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBridgeConfiguration;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceException;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.AirPurifierStateDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.ApplianceDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.ApplianceInfoDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.ApplianceStateDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.WashingMachineStateDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.listener.TokenUpdateListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxGroupAPI} class defines the Elextrolux Group API
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxGroupAPI {
|
||||
|
||||
private static final String BASE_URL = "https://api.developer.electrolux.one";
|
||||
private static final String TOKEN_URL = BASE_URL + "/api/v1/token/refresh";
|
||||
private static final String APPLIANCES_URL = BASE_URL + "/api/v1/appliances";
|
||||
|
||||
private static final int MAX_RETRIES = 3;
|
||||
private static final int REQUEST_TIMEOUT_MS = 10_000;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ElectroluxGroupAPI.class);
|
||||
private final Gson gson;
|
||||
private final HttpClient httpClient;
|
||||
private final ElectroluxApplianceBridgeConfiguration configuration;
|
||||
private String accessToken = "";
|
||||
private Instant tokenExpiry = Instant.MAX;
|
||||
private final TokenUpdateListener tokenUpdateListener;
|
||||
|
||||
public ElectroluxGroupAPI(ElectroluxApplianceBridgeConfiguration configuration, Gson gson, HttpClient httpClient,
|
||||
TokenUpdateListener listener) {
|
||||
this.gson = gson;
|
||||
this.configuration = configuration;
|
||||
this.httpClient = httpClient;
|
||||
this.tokenUpdateListener = listener;
|
||||
}
|
||||
|
||||
public boolean refresh(Map<String, ApplianceDTO> electroluxApplianceThings, boolean isCommunicationError) {
|
||||
try {
|
||||
if (Instant.now().isAfter(this.tokenExpiry) || isCommunicationError) {
|
||||
logger.debug("Is communication error: {}", isCommunicationError);
|
||||
// Refresh since token has expired
|
||||
refreshToken();
|
||||
} else {
|
||||
logger.debug("Now: {} Token expiry: {}", Instant.now(), this.tokenExpiry);
|
||||
|
||||
}
|
||||
// Get all appliances
|
||||
String json = getAppliances();
|
||||
ApplianceDTO[] dtos = gson.fromJson(json, ApplianceDTO[].class);
|
||||
if (dtos != null) {
|
||||
for (ApplianceDTO dto : dtos) {
|
||||
String applianceId = dto.getApplianceId();
|
||||
// Get appliance info
|
||||
String jsonApplianceInfo = getApplianceInfo(applianceId);
|
||||
ApplianceInfoDTO applianceInfo = gson.fromJson(jsonApplianceInfo, ApplianceInfoDTO.class);
|
||||
if (applianceInfo != null) {
|
||||
dto.setApplianceInfo(applianceInfo);
|
||||
if ("AIR_PURIFIER".equals(applianceInfo.getApplianceInfo().getDeviceType())) {
|
||||
// Get appliance state
|
||||
String jsonApplianceState = getApplianceState(applianceId);
|
||||
ApplianceStateDTO applianceState = gson.fromJson(jsonApplianceState,
|
||||
AirPurifierStateDTO.class);
|
||||
if (applianceState != null) {
|
||||
dto.setApplianceState(applianceState);
|
||||
}
|
||||
electroluxApplianceThings.put(applianceInfo.getApplianceInfo().getSerialNumber(), dto);
|
||||
} else if ("WASHING_MACHINE".equals(applianceInfo.getApplianceInfo().getDeviceType())) {
|
||||
// Get appliance state
|
||||
String jsonApplianceState = getApplianceState(applianceId);
|
||||
ApplianceStateDTO applianceState = gson.fromJson(jsonApplianceState,
|
||||
WashingMachineStateDTO.class);
|
||||
if (applianceState != null) {
|
||||
dto.setApplianceState(applianceState);
|
||||
}
|
||||
electroluxApplianceThings.put(applianceInfo.getApplianceInfo().getSerialNumber(), dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (JsonSyntaxException | ElectroluxApplianceException e) {
|
||||
logger.warn("Failed to refresh! {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean workModePowerOff(String applianceId) {
|
||||
String commandJSON = "{ \"Workmode\": \"PowerOff\" }";
|
||||
try {
|
||||
return sendCommand(commandJSON, applianceId);
|
||||
} catch (ElectroluxApplianceException e) {
|
||||
logger.warn("Work mode powerOff failed {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean workModeAuto(String applianceId) {
|
||||
String commandJSON = "{ \"Workmode\": \"Auto\" }";
|
||||
try {
|
||||
return sendCommand(commandJSON, applianceId);
|
||||
} catch (ElectroluxApplianceException e) {
|
||||
logger.warn("Work mode auto failed {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean workModeManual(String applianceId) {
|
||||
String commandJSON = "{ \"Workmode\": \"Manual\" }";
|
||||
try {
|
||||
return sendCommand(commandJSON, applianceId);
|
||||
} catch (ElectroluxApplianceException e) {
|
||||
logger.warn("Work mode manual failed {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setFanSpeedLevel(String applianceId, int fanSpeedLevel) {
|
||||
if (fanSpeedLevel < 1 && fanSpeedLevel > 10) {
|
||||
return false;
|
||||
} else {
|
||||
String commandJSON = "{ \"Fanspeed\": " + fanSpeedLevel + "}";
|
||||
try {
|
||||
return sendCommand(commandJSON, applianceId);
|
||||
} catch (ElectroluxApplianceException e) {
|
||||
logger.warn("Work mode manual failed {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setIonizer(String applianceId, String ionizerStatus) {
|
||||
String commandJSON = "{ \"Ionizer\": " + ionizerStatus + "}";
|
||||
try {
|
||||
return sendCommand(commandJSON, applianceId);
|
||||
} catch (ElectroluxApplianceException e) {
|
||||
logger.warn("Work mode manual failed {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setUILight(String applianceId, String uiLightStatus) {
|
||||
String commandJSON = "{ \"UILight\": " + uiLightStatus + "}";
|
||||
try {
|
||||
return sendCommand(commandJSON, applianceId);
|
||||
} catch (ElectroluxApplianceException e) {
|
||||
logger.warn("Work mode manual failed {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setSafetyLock(String applianceId, String safetyLockStatus) {
|
||||
String commandJSON = "{ \"SafetyLock\": " + safetyLockStatus + "}";
|
||||
try {
|
||||
return sendCommand(commandJSON, applianceId);
|
||||
} catch (ElectroluxApplianceException e) {
|
||||
logger.warn("Work mode manual failed {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Request createRequest(String uri, HttpMethod httpMethod) {
|
||||
Request request = httpClient.newRequest(uri).method(httpMethod);
|
||||
request.timeout(REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
request.header(HttpHeader.ACCEPT, MediaType.APPLICATION_JSON);
|
||||
request.header(HttpHeader.CONTENT_TYPE, MediaType.APPLICATION_JSON);
|
||||
|
||||
logger.trace("HTTP Request {}.", request.toString());
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
private void refreshToken() throws ElectroluxApplianceException {
|
||||
try {
|
||||
String json = "{\"refreshToken\": \"" + this.configuration.refreshToken + "\"}";
|
||||
Request request = createRequest(TOKEN_URL, HttpMethod.POST);
|
||||
request.content(new StringContentProvider(json), MediaType.APPLICATION_JSON);
|
||||
logger.debug("HTTP POST Request {}.", request.toString());
|
||||
ContentResponse httpResponse;
|
||||
httpResponse = request.send();
|
||||
if (httpResponse.getStatus() != HttpStatus.OK_200) {
|
||||
throw new ElectroluxApplianceException("Failed to refresh tokens" + httpResponse.getContentAsString());
|
||||
}
|
||||
json = httpResponse.getContentAsString();
|
||||
logger.trace("Tokens: {}", json);
|
||||
JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
|
||||
this.accessToken = jsonObject.get("accessToken").getAsString();
|
||||
this.configuration.refreshToken = jsonObject.get("refreshToken").getAsString();
|
||||
// Notify the listener about the updated tokens
|
||||
tokenUpdateListener.onTokenUpdated(this.configuration.refreshToken);
|
||||
long expiresIn = jsonObject.get("expiresIn").getAsLong();
|
||||
logger.debug("Token expires in: {}s", expiresIn);
|
||||
this.tokenExpiry = Instant.now().plusSeconds(expiresIn);
|
||||
logger.debug("Token expires: {}", this.tokenExpiry);
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException e) {
|
||||
throw new ElectroluxApplianceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFromApi(String uri) throws ElectroluxApplianceException, InterruptedException {
|
||||
try {
|
||||
for (int i = 0; i < MAX_RETRIES; i++) {
|
||||
try {
|
||||
Request request = createRequest(uri, HttpMethod.GET);
|
||||
request.header("x-api-key", this.configuration.apiKey);
|
||||
request.header(HttpHeader.AUTHORIZATION, "Bearer " + this.accessToken);
|
||||
logger.trace("Request header {}", request);
|
||||
|
||||
ContentResponse response = request.send();
|
||||
String content = response.getContentAsString();
|
||||
logger.trace("API response: {}", content);
|
||||
|
||||
if (response.getStatus() != HttpStatus.OK_200) {
|
||||
logger.debug("getFromApi failed, HTTP status: {}", response.getStatus());
|
||||
refreshToken();
|
||||
} else {
|
||||
return content;
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
logger.debug("TimeoutException error in get: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
throw new ElectroluxApplianceException("Failed to fetch from API!");
|
||||
} catch (JsonSyntaxException | ElectroluxApplianceException | ExecutionException e) {
|
||||
throw new ElectroluxApplianceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getAppliances() throws ElectroluxApplianceException {
|
||||
try {
|
||||
return getFromApi(APPLIANCES_URL);
|
||||
} catch (ElectroluxApplianceException | InterruptedException e) {
|
||||
throw new ElectroluxApplianceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getApplianceInfo(String applianceId) throws ElectroluxApplianceException {
|
||||
try {
|
||||
return getFromApi(APPLIANCES_URL + "/" + applianceId + "/info");
|
||||
} catch (ElectroluxApplianceException | InterruptedException e) {
|
||||
throw new ElectroluxApplianceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getApplianceState(String applianceId) throws ElectroluxApplianceException {
|
||||
try {
|
||||
return getFromApi(APPLIANCES_URL + "/" + applianceId + "/state");
|
||||
} catch (ElectroluxApplianceException | InterruptedException e) {
|
||||
throw new ElectroluxApplianceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendCommand(String commandJSON, String applianceId) throws ElectroluxApplianceException {
|
||||
try {
|
||||
for (int i = 0; i < MAX_RETRIES; i++) {
|
||||
try {
|
||||
Request request = createRequest(APPLIANCES_URL + "/" + applianceId + "/command", HttpMethod.PUT);
|
||||
request.header(HttpHeader.AUTHORIZATION, "Bearer " + this.accessToken);
|
||||
request.header("x-api-key", this.configuration.apiKey);
|
||||
request.content(new StringContentProvider(commandJSON), MediaType.APPLICATION_JSON);
|
||||
logger.trace("Command JSON: {}", commandJSON);
|
||||
|
||||
ContentResponse response = request.send();
|
||||
String content = response.getContentAsString();
|
||||
logger.trace("API response: {}", content);
|
||||
|
||||
if (response.getStatus() != HttpStatus.OK_200) {
|
||||
logger.debug("sendCommand failed, HTTP status: {}", response.getStatus());
|
||||
refreshToken();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (TimeoutException | InterruptedException e) {
|
||||
logger.warn("TimeoutException error in get");
|
||||
}
|
||||
}
|
||||
} catch (JsonSyntaxException | ElectroluxApplianceException | ExecutionException e) {
|
||||
throw new ElectroluxApplianceException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceConfiguration;
|
||||
import org.openhab.binding.electroluxappliance.internal.handler.ElectroluxApplianceBridgeHandler;
|
||||
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.ServiceScope;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxApplianceDiscoveryService} searches for available
|
||||
* Electrolux Pure A9 discoverable through Electrolux Delta API.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@Component(scope = ServiceScope.PROTOTYPE, service = ElectroluxApplianceDiscoveryService.class)
|
||||
@NonNullByDefault
|
||||
public class ElectroluxApplianceDiscoveryService
|
||||
extends AbstractThingHandlerDiscoveryService<ElectroluxApplianceBridgeHandler> {
|
||||
private static final int SEARCH_TIME = 10;
|
||||
|
||||
public ElectroluxApplianceDiscoveryService() {
|
||||
super(ElectroluxApplianceBridgeHandler.class, SUPPORTED_THING_TYPES_UIDS, SEARCH_TIME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
ThingUID bridgeUID = thingHandler.getThing().getUID();
|
||||
thingHandler.getElectroluxApplianceThings().entrySet().stream().forEach(thing -> {
|
||||
String applianceType = thing.getValue().getApplianceType();
|
||||
|
||||
if ("PUREA9".equalsIgnoreCase(applianceType)) {
|
||||
thingDiscovered(DiscoveryResultBuilder
|
||||
.create(new ThingUID(THING_TYPE_ELECTROLUX_AIR_PURIFIER, bridgeUID, thing.getKey()))
|
||||
.withLabel("Electrolux Pure A9").withBridge(bridgeUID)
|
||||
.withProperty(ElectroluxApplianceConfiguration.SERIAL_NUMBER_LABEL, thing.getKey())
|
||||
.withRepresentationProperty(ElectroluxApplianceConfiguration.SERIAL_NUMBER_LABEL).build());
|
||||
} else if ("WM".equalsIgnoreCase(applianceType)) {
|
||||
thingDiscovered(DiscoveryResultBuilder
|
||||
.create(new ThingUID(THING_TYPE_ELECTROLUX_WASHING_MACHINE, bridgeUID, thing.getKey()))
|
||||
.withLabel("Electrolux Washing Machine").withBridge(bridgeUID)
|
||||
.withProperty(ElectroluxApplianceConfiguration.SERIAL_NUMBER_LABEL, thing.getKey())
|
||||
.withRepresentationProperty(ElectroluxApplianceConfiguration.SERIAL_NUMBER_LABEL).build());
|
||||
}
|
||||
});
|
||||
|
||||
stopScan();
|
||||
}
|
||||
}
|
@ -0,0 +1,346 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link AirPurifierStateDTO} class defines the DTO for the Electrolux Purifiers.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AirPurifierStateDTO extends ApplianceStateDTO {
|
||||
|
||||
@SerializedName("properties")
|
||||
private Properties properties = new Properties();
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
// Inner class for Properties
|
||||
public static class Properties {
|
||||
@SerializedName("reported")
|
||||
private Reported reported = new Reported();
|
||||
|
||||
public Reported getReported() {
|
||||
return reported;
|
||||
}
|
||||
}
|
||||
|
||||
// Inner class for Reported properties
|
||||
public static class Reported {
|
||||
@SerializedName("FrmVer_NIU")
|
||||
private String frmVerNIU = "";
|
||||
|
||||
@SerializedName("Workmode")
|
||||
private String workmode = "";
|
||||
|
||||
@SerializedName("FilterRFID")
|
||||
private String filterRFID = "";
|
||||
|
||||
@SerializedName("FilterLife")
|
||||
private int filterLife;
|
||||
|
||||
@SerializedName("Fanspeed")
|
||||
private int fanspeed;
|
||||
|
||||
@SerializedName("UILight")
|
||||
private boolean uiLight;
|
||||
|
||||
@SerializedName("SafetyLock")
|
||||
private boolean safetyLock;
|
||||
|
||||
@SerializedName("Ionizer")
|
||||
private boolean ionizer;
|
||||
|
||||
@SerializedName("Sleep")
|
||||
private boolean sleep;
|
||||
|
||||
@SerializedName("Scheduler")
|
||||
private boolean scheduler;
|
||||
|
||||
@SerializedName("FilterType")
|
||||
private int filterType;
|
||||
|
||||
@SerializedName("DspIcoPM2_5")
|
||||
private boolean dspIcoPM25;
|
||||
|
||||
@SerializedName("DspIcoPM1")
|
||||
private boolean dspIcoPM1;
|
||||
|
||||
@SerializedName("DspIcoPM10")
|
||||
private boolean dspIcoPM10;
|
||||
|
||||
@SerializedName("DspIcoTVOC")
|
||||
private boolean dspIcoTVOC;
|
||||
|
||||
@SerializedName("ErrPM2_5")
|
||||
private boolean errPM25;
|
||||
|
||||
@SerializedName("ErrTVOC")
|
||||
private boolean errTVOC;
|
||||
|
||||
@SerializedName("ErrTempHumidity")
|
||||
private boolean errTempHumidity;
|
||||
|
||||
@SerializedName("ErrFanMtr")
|
||||
private boolean errFanMtr;
|
||||
|
||||
@SerializedName("ErrCommSensorDisplayBrd")
|
||||
private boolean errCommSensorDisplayBrd;
|
||||
|
||||
@SerializedName("DoorOpen")
|
||||
private boolean doorOpen;
|
||||
|
||||
@SerializedName("ErrRFID")
|
||||
private boolean errRFID;
|
||||
|
||||
@SerializedName("SignalStrength")
|
||||
private String signalStrength = "";
|
||||
|
||||
@SerializedName("logE")
|
||||
private int logE;
|
||||
|
||||
@SerializedName("logW")
|
||||
private int logW;
|
||||
|
||||
@SerializedName("InterfaceVer")
|
||||
private int interfaceVer;
|
||||
|
||||
@SerializedName("VmNo_NIU")
|
||||
private String vmNoNIU = "";
|
||||
|
||||
@SerializedName("TVOCBrand")
|
||||
private String tvocBrand = "";
|
||||
|
||||
private Capabilities capabilities = new Capabilities();
|
||||
|
||||
private Tasks tasks = new Tasks();
|
||||
|
||||
@SerializedName("$version")
|
||||
private int version;
|
||||
|
||||
private String deviceId = "";
|
||||
|
||||
@SerializedName("CO2")
|
||||
private int co2;
|
||||
|
||||
@SerializedName("TVOC")
|
||||
private int tvoc;
|
||||
|
||||
@SerializedName("Temp")
|
||||
private int temp;
|
||||
|
||||
@SerializedName("Humidity")
|
||||
private int humidity;
|
||||
|
||||
@SerializedName("RSSI")
|
||||
private int rssi;
|
||||
|
||||
@SerializedName("PM1")
|
||||
private int pm1;
|
||||
|
||||
@SerializedName("PM2_5")
|
||||
private int pm25;
|
||||
|
||||
@SerializedName("PM10")
|
||||
private int pm10;
|
||||
|
||||
@SerializedName("ECO2")
|
||||
private int eco2;
|
||||
|
||||
// Getters for all fields
|
||||
public String getFrmVerNIU() {
|
||||
return frmVerNIU;
|
||||
}
|
||||
|
||||
public String getWorkmode() {
|
||||
return workmode;
|
||||
}
|
||||
|
||||
public String getFilterRFID() {
|
||||
return filterRFID;
|
||||
}
|
||||
|
||||
public int getFilterLife() {
|
||||
return filterLife;
|
||||
}
|
||||
|
||||
public int getFanspeed() {
|
||||
return fanspeed;
|
||||
}
|
||||
|
||||
public boolean isUiLight() {
|
||||
return uiLight;
|
||||
}
|
||||
|
||||
public boolean isSafetyLock() {
|
||||
return safetyLock;
|
||||
}
|
||||
|
||||
public boolean isIonizer() {
|
||||
return ionizer;
|
||||
}
|
||||
|
||||
public boolean isSleep() {
|
||||
return sleep;
|
||||
}
|
||||
|
||||
public boolean isScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public int getFilterType() {
|
||||
return filterType;
|
||||
}
|
||||
|
||||
public boolean isDspIcoPM25() {
|
||||
return dspIcoPM25;
|
||||
}
|
||||
|
||||
public boolean isDspIcoPM1() {
|
||||
return dspIcoPM1;
|
||||
}
|
||||
|
||||
public boolean isDspIcoPM10() {
|
||||
return dspIcoPM10;
|
||||
}
|
||||
|
||||
public boolean isDspIcoTVOC() {
|
||||
return dspIcoTVOC;
|
||||
}
|
||||
|
||||
public boolean isErrPM25() {
|
||||
return errPM25;
|
||||
}
|
||||
|
||||
public boolean isErrTVOC() {
|
||||
return errTVOC;
|
||||
}
|
||||
|
||||
public boolean isErrTempHumidity() {
|
||||
return errTempHumidity;
|
||||
}
|
||||
|
||||
public boolean isErrFanMtr() {
|
||||
return errFanMtr;
|
||||
}
|
||||
|
||||
public boolean isErrCommSensorDisplayBrd() {
|
||||
return errCommSensorDisplayBrd;
|
||||
}
|
||||
|
||||
public boolean isDoorOpen() {
|
||||
return doorOpen;
|
||||
}
|
||||
|
||||
public boolean isErrRFID() {
|
||||
return errRFID;
|
||||
}
|
||||
|
||||
public String getSignalStrength() {
|
||||
return signalStrength;
|
||||
}
|
||||
|
||||
public int getLogE() {
|
||||
return logE;
|
||||
}
|
||||
|
||||
public int getLogW() {
|
||||
return logW;
|
||||
}
|
||||
|
||||
public int getInterfaceVer() {
|
||||
return interfaceVer;
|
||||
}
|
||||
|
||||
public String getVmNoNIU() {
|
||||
return vmNoNIU;
|
||||
}
|
||||
|
||||
public String getTvocBrand() {
|
||||
return tvocBrand;
|
||||
}
|
||||
|
||||
public Capabilities getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public Tasks getTasks() {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public int getCo2() {
|
||||
return co2;
|
||||
}
|
||||
|
||||
public int getTvoc() {
|
||||
return tvoc;
|
||||
}
|
||||
|
||||
public int getTemp() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
public int getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public int getRssi() {
|
||||
return rssi;
|
||||
}
|
||||
|
||||
public int getPm1() {
|
||||
return pm1;
|
||||
}
|
||||
|
||||
public int getPm25() {
|
||||
return pm25;
|
||||
}
|
||||
|
||||
public int getPm10() {
|
||||
return pm10;
|
||||
}
|
||||
|
||||
public int getEco2() {
|
||||
return eco2;
|
||||
}
|
||||
}
|
||||
|
||||
// Inner class for Capabilities
|
||||
public static class Capabilities {
|
||||
@SerializedName("tasks")
|
||||
private Tasks tasks = new Tasks();
|
||||
|
||||
public Tasks getTasks() {
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
|
||||
// Inner class for Tasks (assuming it's empty as shown in the JSON)
|
||||
public static class Tasks {
|
||||
// No fields; can be extended as needed
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ApplianceDTO} class defines the DTO for the Electrolux Appliances.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ApplianceDTO {
|
||||
private String applianceId = "";
|
||||
private String applianceName = "";
|
||||
private String applianceType = "";
|
||||
private String created = "";
|
||||
private ApplianceInfoDTO applianceInfo = new ApplianceInfoDTO();
|
||||
private ApplianceStateDTO applianceState = new ApplianceStateDTO();
|
||||
|
||||
public void setApplianceInfo(ApplianceInfoDTO applianceInfo) {
|
||||
this.applianceInfo = applianceInfo;
|
||||
}
|
||||
|
||||
public void setApplianceState(ApplianceStateDTO applianceState) {
|
||||
this.applianceState = applianceState;
|
||||
}
|
||||
|
||||
public ApplianceInfoDTO getApplianceInfo() {
|
||||
return applianceInfo;
|
||||
}
|
||||
|
||||
public ApplianceStateDTO getApplianceState() {
|
||||
return applianceState;
|
||||
}
|
||||
|
||||
// Getters for each field
|
||||
public String getApplianceId() {
|
||||
return applianceId;
|
||||
}
|
||||
|
||||
public String getApplianceName() {
|
||||
return applianceName;
|
||||
}
|
||||
|
||||
public String getApplianceType() {
|
||||
return applianceType;
|
||||
}
|
||||
|
||||
public String getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
// Optional toString method for easier debugging and logging
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Appliance{" + "applianceId='" + applianceId + '\'' + ", applianceName='" + applianceName + '\''
|
||||
+ ", applianceType='" + applianceType + '\'' + ", created='" + created + '\'' + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ApplianceInfoDTO} class defines the DTO for the Electrolux Appliance Info.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class ApplianceInfoDTO {
|
||||
|
||||
private ApplianceInfo applianceInfo = new ApplianceInfo();
|
||||
|
||||
// Map capabilities to Object, so details are not parsed
|
||||
private Object capabilities = new Object();
|
||||
|
||||
public ApplianceInfo getApplianceInfo() {
|
||||
return applianceInfo;
|
||||
}
|
||||
|
||||
public Object getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public static class ApplianceInfo {
|
||||
private String serialNumber = "";
|
||||
private String pnc = "";
|
||||
private String brand = "";
|
||||
private String deviceType = "";
|
||||
private String model = "";
|
||||
private String variant = "";
|
||||
private String colour = "";
|
||||
|
||||
// Getters
|
||||
public String getSerialNumber() {
|
||||
return serialNumber;
|
||||
}
|
||||
|
||||
public String getPnc() {
|
||||
return pnc;
|
||||
}
|
||||
|
||||
public String getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public String getVariant() {
|
||||
return variant;
|
||||
}
|
||||
|
||||
public String getColour() {
|
||||
return colour;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApplianceInfo{" + "serialNumber='" + serialNumber + '\'' + ", pnc='" + pnc + '\'' + ", brand='"
|
||||
+ brand + '\'' + ", deviceType='" + deviceType + '\'' + ", model='" + model + '\'' + ", variant='"
|
||||
+ variant + '\'' + ", colour='" + colour + '\'' + '}';
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ApplianceStateDTO} class defines the DTO for the Electrolux Appliance State.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ApplianceStateDTO {
|
||||
private String applianceId = "";
|
||||
private String connectionState = "";
|
||||
private String status = "";
|
||||
|
||||
public String getApplianceId() {
|
||||
return applianceId;
|
||||
}
|
||||
|
||||
public String getConnectionState() {
|
||||
return connectionState;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
// You can optionally add a toString() method for easier debugging
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApplianceStateDTO{" + "applianceId='" + applianceId + '\'' + ", connectionState='" + connectionState
|
||||
+ '\'' + ", status='" + status + '\'' + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,496 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link AirPurifierStateDTO} class defines the DTO for the Electrolux Washing Machines.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WashingMachineStateDTO extends ApplianceStateDTO {
|
||||
|
||||
private Properties properties = new Properties();
|
||||
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static class Properties {
|
||||
private Reported reported = new Reported();
|
||||
|
||||
public Reported getReported() {
|
||||
return reported;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Reported {
|
||||
private String displayLight = "";
|
||||
private String doorState = "";
|
||||
private int timeToEnd;
|
||||
private Miscellaneous miscellaneous = new Miscellaneous();
|
||||
private String applianceUiSwVersion = "";
|
||||
private int applianceTotalWorkingTime;
|
||||
private String remoteControl = "";
|
||||
private String language = "";
|
||||
private FCMiscellaneousState fCMiscellaneousState = new FCMiscellaneousState();
|
||||
private String cyclePhase = "";
|
||||
private String endOfCycleSound = "";
|
||||
private int startTime;
|
||||
private UserSelections userSelections = new UserSelections();
|
||||
private String waterHardness = "";
|
||||
private String defaultExtraRinse = "";
|
||||
private int totalWashingTime;
|
||||
private ApplianceInfo applianceInfo = new ApplianceInfo();
|
||||
private String doorLock = "";
|
||||
private boolean uiLockMode;
|
||||
private int washingNominalLoadWeight;
|
||||
private int totalWashCyclesCount;
|
||||
private int fcOptisenseLoadWeight;
|
||||
private String waterSoftenerMode = "";
|
||||
private String applianceState = "";
|
||||
private String applianceMode = "";
|
||||
private String applianceMainBoardSwVersion = "";
|
||||
private int totalCycleCounter;
|
||||
private int measuredLoadWeight;
|
||||
private Object[] alerts = new Object[0];
|
||||
private Maintenance applianceCareAndMaintenance0 = new Maintenance();
|
||||
private NetworkInterface networkInterface = new NetworkInterface();
|
||||
private Maintenance applianceCareAndMaintenance1 = new Maintenance();
|
||||
private Maintenance applianceCareAndMaintenance2 = new Maintenance();
|
||||
private Maintenance applianceCareAndMaintenance3 = new Maintenance();
|
||||
private AutoDosing autoDosing = new AutoDosing();
|
||||
private String cycleSubPhase = "";
|
||||
private String connectivityState = "";
|
||||
|
||||
// Getters for all fields
|
||||
public String getDisplayLight() {
|
||||
return displayLight;
|
||||
}
|
||||
|
||||
public String getDoorState() {
|
||||
return doorState;
|
||||
}
|
||||
|
||||
public int getTimeToEnd() {
|
||||
return timeToEnd;
|
||||
}
|
||||
|
||||
public Miscellaneous getMiscellaneous() {
|
||||
return miscellaneous;
|
||||
}
|
||||
|
||||
public String getApplianceUiSwVersion() {
|
||||
return applianceUiSwVersion;
|
||||
}
|
||||
|
||||
public int getApplianceTotalWorkingTime() {
|
||||
return applianceTotalWorkingTime;
|
||||
}
|
||||
|
||||
public String getRemoteControl() {
|
||||
return remoteControl;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public FCMiscellaneousState getFCMiscellaneousState() {
|
||||
return fCMiscellaneousState;
|
||||
}
|
||||
|
||||
public String getCyclePhase() {
|
||||
return cyclePhase;
|
||||
}
|
||||
|
||||
public String getEndOfCycleSound() {
|
||||
return endOfCycleSound;
|
||||
}
|
||||
|
||||
public int getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public UserSelections getUserSelections() {
|
||||
return userSelections;
|
||||
}
|
||||
|
||||
public String getWaterHardness() {
|
||||
return waterHardness;
|
||||
}
|
||||
|
||||
public String getDefaultExtraRinse() {
|
||||
return defaultExtraRinse;
|
||||
}
|
||||
|
||||
public int getTotalWashingTime() {
|
||||
return totalWashingTime;
|
||||
}
|
||||
|
||||
public ApplianceInfo getApplianceInfo() {
|
||||
return applianceInfo;
|
||||
}
|
||||
|
||||
public String getDoorLock() {
|
||||
return doorLock;
|
||||
}
|
||||
|
||||
public boolean isUiLockMode() {
|
||||
return uiLockMode;
|
||||
}
|
||||
|
||||
public int getWashingNominalLoadWeight() {
|
||||
return washingNominalLoadWeight;
|
||||
}
|
||||
|
||||
public int getTotalWashCyclesCount() {
|
||||
return totalWashCyclesCount;
|
||||
}
|
||||
|
||||
public int getFcOptisenseLoadWeight() {
|
||||
return fcOptisenseLoadWeight;
|
||||
}
|
||||
|
||||
public String getWaterSoftenerMode() {
|
||||
return waterSoftenerMode;
|
||||
}
|
||||
|
||||
public String getApplianceState() {
|
||||
return applianceState;
|
||||
}
|
||||
|
||||
public String getApplianceMode() {
|
||||
return applianceMode;
|
||||
}
|
||||
|
||||
public String getApplianceMainBoardSwVersion() {
|
||||
return applianceMainBoardSwVersion;
|
||||
}
|
||||
|
||||
public int getTotalCycleCounter() {
|
||||
return totalCycleCounter;
|
||||
}
|
||||
|
||||
public int getMeasuredLoadWeight() {
|
||||
return measuredLoadWeight;
|
||||
}
|
||||
|
||||
public Object[] getAlerts() {
|
||||
return alerts;
|
||||
}
|
||||
|
||||
public Maintenance getApplianceCareAndMaintenance0() {
|
||||
return applianceCareAndMaintenance0;
|
||||
}
|
||||
|
||||
public NetworkInterface getNetworkInterface() {
|
||||
return networkInterface;
|
||||
}
|
||||
|
||||
public Maintenance getApplianceCareAndMaintenance1() {
|
||||
return applianceCareAndMaintenance1;
|
||||
}
|
||||
|
||||
public Maintenance getApplianceCareAndMaintenance2() {
|
||||
return applianceCareAndMaintenance2;
|
||||
}
|
||||
|
||||
public Maintenance getApplianceCareAndMaintenance3() {
|
||||
return applianceCareAndMaintenance3;
|
||||
}
|
||||
|
||||
public AutoDosing getAutoDosing() {
|
||||
return autoDosing;
|
||||
}
|
||||
|
||||
public String getCycleSubPhase() {
|
||||
return cycleSubPhase;
|
||||
}
|
||||
|
||||
public String getConnectivityState() {
|
||||
return connectivityState;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Miscellaneous {
|
||||
private boolean defaultSoftPlus;
|
||||
|
||||
public boolean isDefaultSoftPlus() {
|
||||
return defaultSoftPlus;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FCMiscellaneousState {
|
||||
private int optisenseResult;
|
||||
private int detergentExtradosage;
|
||||
private boolean tankAReserve;
|
||||
private boolean tankBReserve;
|
||||
private int softenerExtradosage;
|
||||
private int waterUsage;
|
||||
private int tankADetLoadForNominalWeight;
|
||||
private int tankBDetLoadForNominalWeight;
|
||||
|
||||
public int getOptisenseResult() {
|
||||
return optisenseResult;
|
||||
}
|
||||
|
||||
public int getDetergentExtradosage() {
|
||||
return detergentExtradosage;
|
||||
}
|
||||
|
||||
public boolean isTankAReserve() {
|
||||
return tankAReserve;
|
||||
}
|
||||
|
||||
public boolean isTankBReserve() {
|
||||
return tankBReserve;
|
||||
}
|
||||
|
||||
public int getSoftenerExtradosage() {
|
||||
return softenerExtradosage;
|
||||
}
|
||||
|
||||
public int getWaterUsage() {
|
||||
return waterUsage;
|
||||
}
|
||||
|
||||
public int getTankADetLoadForNominalWeight() {
|
||||
return tankADetLoadForNominalWeight;
|
||||
}
|
||||
|
||||
public int getTankBDetLoadForNominalWeight() {
|
||||
return tankBDetLoadForNominalWeight;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserSelections {
|
||||
private boolean EWX1493A_ultraMix;
|
||||
private boolean EWX1493A_stain;
|
||||
private String adTankBSel = "";
|
||||
private String adFineTuneSoftLevel = "";
|
||||
private boolean EWX1493A_wetMode;
|
||||
private String analogSpinSpeed = "";
|
||||
private boolean EWX1493A_easyIron;
|
||||
private boolean EWX1493A_rinseHold;
|
||||
private boolean EWX1493A_wmEconomy;
|
||||
private boolean EWX1493A_tcSensor;
|
||||
private String programUID = "";
|
||||
private boolean EWX1493A_anticreaseNoSteam;
|
||||
private boolean EWX1493A_anticreaseWSteam;
|
||||
private String adTankASel = "";
|
||||
private String timeManagerLevel = "";
|
||||
private boolean EWX1493A_dryMode;
|
||||
private boolean EWX1493A_preWashPhase;
|
||||
private String extraRinseNumber = "";
|
||||
private String adFineTuneDetLevel = "";
|
||||
private boolean EWX1493A_steamMode;
|
||||
private String analogTemperature = "";
|
||||
private boolean EWX1493A_nightCycle;
|
||||
private String steamValue = "";
|
||||
private boolean EWX1493A_intensive;
|
||||
private boolean EWX1493A_pod;
|
||||
|
||||
public boolean isEWX1493A_ultraMix() {
|
||||
return EWX1493A_ultraMix;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_stain() {
|
||||
return EWX1493A_stain;
|
||||
}
|
||||
|
||||
public String getAdTankBSel() {
|
||||
return adTankBSel;
|
||||
}
|
||||
|
||||
public String getAdFineTuneSoftLevel() {
|
||||
return adFineTuneSoftLevel;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_wetMode() {
|
||||
return EWX1493A_wetMode;
|
||||
}
|
||||
|
||||
public String getAnalogSpinSpeed() {
|
||||
return analogSpinSpeed;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_easyIron() {
|
||||
return EWX1493A_easyIron;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_rinseHold() {
|
||||
return EWX1493A_rinseHold;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_wmEconomy() {
|
||||
return EWX1493A_wmEconomy;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_tcSensor() {
|
||||
return EWX1493A_tcSensor;
|
||||
}
|
||||
|
||||
public String getProgramUID() {
|
||||
return programUID;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_anticreaseNoSteam() {
|
||||
return EWX1493A_anticreaseNoSteam;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_anticreaseWSteam() {
|
||||
return EWX1493A_anticreaseWSteam;
|
||||
}
|
||||
|
||||
public String getAdTankASel() {
|
||||
return adTankASel;
|
||||
}
|
||||
|
||||
public String getTimeManagerLevel() {
|
||||
return timeManagerLevel;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_dryMode() {
|
||||
return EWX1493A_dryMode;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_preWashPhase() {
|
||||
return EWX1493A_preWashPhase;
|
||||
}
|
||||
|
||||
public String getExtraRinseNumber() {
|
||||
return extraRinseNumber;
|
||||
}
|
||||
|
||||
public String getAdFineTuneDetLevel() {
|
||||
return adFineTuneDetLevel;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_steamMode() {
|
||||
return EWX1493A_steamMode;
|
||||
}
|
||||
|
||||
public String getAnalogTemperature() {
|
||||
return analogTemperature;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_nightCycle() {
|
||||
return EWX1493A_nightCycle;
|
||||
}
|
||||
|
||||
public String getSteamValue() {
|
||||
return steamValue;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_intensive() {
|
||||
return EWX1493A_intensive;
|
||||
}
|
||||
|
||||
public boolean isEWX1493A_pod() {
|
||||
return EWX1493A_pod;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ApplianceInfo {
|
||||
private String applianceType = "";
|
||||
|
||||
public String getApplianceType() {
|
||||
return applianceType;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Maintenance {
|
||||
private CareThreshold careThreshold = new CareThreshold();
|
||||
|
||||
public CareThreshold getCareThreshold() {
|
||||
return careThreshold;
|
||||
}
|
||||
|
||||
public static class CareThreshold {
|
||||
private boolean occurred;
|
||||
private int threshold;
|
||||
|
||||
public boolean isOccurred() {
|
||||
return occurred;
|
||||
}
|
||||
|
||||
public int getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class NetworkInterface {
|
||||
private String swVersion = "";
|
||||
private String linkQualityIndicator = "";
|
||||
private String otaState = "";
|
||||
private String niuSwUpdateCurrentDescription = "";
|
||||
private String swAncAndRevision = "";
|
||||
|
||||
public String getSwVersion() {
|
||||
return swVersion;
|
||||
}
|
||||
|
||||
public String getLinkQualityIndicator() {
|
||||
return linkQualityIndicator;
|
||||
}
|
||||
|
||||
public String getOtaState() {
|
||||
return otaState;
|
||||
}
|
||||
|
||||
public String getNiuSwUpdateCurrentDescription() {
|
||||
return niuSwUpdateCurrentDescription;
|
||||
}
|
||||
|
||||
public String getSwAncAndRevision() {
|
||||
return swAncAndRevision;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AutoDosing {
|
||||
private int adTankBDetStandardDose;
|
||||
private boolean adLocalFineTuning;
|
||||
private String adTankAConfiguration = "";
|
||||
private int adTankBSoftStandardDose;
|
||||
private String adTankBConfiguration = "";
|
||||
private int adTankADetStandardDose;
|
||||
|
||||
public int getAdTankBDetStandardDose() {
|
||||
return adTankBDetStandardDose;
|
||||
}
|
||||
|
||||
public boolean isAdLocalFineTuning() {
|
||||
return adLocalFineTuning;
|
||||
}
|
||||
|
||||
public String getAdTankAConfiguration() {
|
||||
return adTankAConfiguration;
|
||||
}
|
||||
|
||||
public int getAdTankBSoftStandardDose() {
|
||||
return adTankBSoftStandardDose;
|
||||
}
|
||||
|
||||
public String getAdTankBConfiguration() {
|
||||
return adTankBConfiguration;
|
||||
}
|
||||
|
||||
public int getAdTankADetStandardDose() {
|
||||
return adTankADetStandardDose;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.handler;
|
||||
|
||||
import static org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBindingConstants;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceConfiguration;
|
||||
import org.openhab.binding.electroluxappliance.internal.api.ElectroluxGroupAPI;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.AirPurifierStateDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.ApplianceDTO;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxAirPurifierHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxAirPurifierHandler extends ElectroluxApplianceHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ElectroluxAirPurifierHandler.class);
|
||||
|
||||
private ElectroluxApplianceConfiguration config = new ElectroluxApplianceConfiguration();
|
||||
|
||||
public ElectroluxAirPurifierHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("Command received: {} on channelID: {}", command, channelUID);
|
||||
if (CHANNEL_STATUS.equals(channelUID.getId()) || command instanceof RefreshType) {
|
||||
super.handleCommand(channelUID, command);
|
||||
} else {
|
||||
ApplianceDTO dto = getApplianceDTO();
|
||||
ElectroluxGroupAPI api = getElectroluxGroupAPI();
|
||||
if (api != null && dto != null) {
|
||||
if (CHANNEL_WORK_MODE.equals(channelUID.getId())) {
|
||||
if (command.toString().equals(COMMAND_WORKMODE_POWEROFF)) {
|
||||
api.workModePowerOff(dto.getApplianceId());
|
||||
} else if (command.toString().equals(COMMAND_WORKMODE_AUTO)) {
|
||||
api.workModeAuto(dto.getApplianceId());
|
||||
} else if (command.toString().equals(COMMAND_WORKMODE_MANUAL)) {
|
||||
api.workModeManual(dto.getApplianceId());
|
||||
}
|
||||
} else if (CHANNEL_FAN_SPEED.equals(channelUID.getId())) {
|
||||
api.setFanSpeedLevel(dto.getApplianceId(), Integer.parseInt(command.toString()));
|
||||
} else if (CHANNEL_IONIZER.equals(channelUID.getId())) {
|
||||
if (command == OnOffType.OFF) {
|
||||
api.setIonizer(dto.getApplianceId(), "false");
|
||||
} else if (command == OnOffType.ON) {
|
||||
api.setIonizer(dto.getApplianceId(), "true");
|
||||
} else {
|
||||
logger.debug("Unknown command! {}", command);
|
||||
}
|
||||
} else if (CHANNEL_UI_LIGHT.equals(channelUID.getId())) {
|
||||
if (command == OnOffType.OFF) {
|
||||
api.setUILight(dto.getApplianceId(), "false");
|
||||
} else if (command == OnOffType.ON) {
|
||||
api.setUILight(dto.getApplianceId(), "true");
|
||||
} else {
|
||||
logger.debug("Unknown command! {}", command);
|
||||
}
|
||||
} else if (CHANNEL_SAFETY_LOCK.equals(channelUID.getId())) {
|
||||
if (command == OnOffType.OFF) {
|
||||
api.setSafetyLock(dto.getApplianceId(), "false");
|
||||
} else if (command == OnOffType.ON) {
|
||||
api.setSafetyLock(dto.getApplianceId(), "true");
|
||||
} else {
|
||||
logger.debug("Unknown command! {}", command);
|
||||
}
|
||||
}
|
||||
|
||||
final Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getHandler() instanceof ElectroluxApplianceBridgeHandler bridgeHandler) {
|
||||
bridgeHandler.handleCommand(
|
||||
new ChannelUID(this.thing.getUID(), ElectroluxApplianceBindingConstants.CHANNEL_STATUS),
|
||||
RefreshType.REFRESH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@Nullable ApplianceDTO dto) {
|
||||
if (dto != null) {
|
||||
// Update all channels from the updated data
|
||||
getThing().getChannels().stream().map(Channel::getUID).filter(channelUID -> isLinked(channelUID))
|
||||
.forEach(channelUID -> {
|
||||
State state = getValue(channelUID.getId(), dto);
|
||||
logger.trace("Channel: {}, State: {}", channelUID, state);
|
||||
updateState(channelUID, state);
|
||||
});
|
||||
if ("Connected".equalsIgnoreCase(dto.getApplianceState().getConnectionState())) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Air Purifier not connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private State getValue(String channelId, ApplianceDTO dto) {
|
||||
var reported = ((AirPurifierStateDTO) dto.getApplianceState()).getProperties().getReported();
|
||||
switch (channelId) {
|
||||
case CHANNEL_TEMPERATURE:
|
||||
return new QuantityType<>(reported.getTemp(), SIUnits.CELSIUS);
|
||||
case CHANNEL_HUMIDITY:
|
||||
return new QuantityType<>(reported.getHumidity(), Units.PERCENT);
|
||||
case CHANNEL_TVOC:
|
||||
return new QuantityType<>(reported.getTvoc(), Units.PARTS_PER_BILLION);
|
||||
case CHANNEL_PM1:
|
||||
return new QuantityType<>(reported.getPm1(), Units.MICROGRAM_PER_CUBICMETRE);
|
||||
case CHANNEL_PM25:
|
||||
return new QuantityType<>(reported.getPm25(), Units.MICROGRAM_PER_CUBICMETRE);
|
||||
case CHANNEL_PM10:
|
||||
return new QuantityType<>(reported.getPm10(), Units.MICROGRAM_PER_CUBICMETRE);
|
||||
case CHANNEL_CO2:
|
||||
return new QuantityType<>(reported.getCo2(), Units.PARTS_PER_MILLION);
|
||||
case CHANNEL_FAN_SPEED:
|
||||
return new StringType(Integer.toString(reported.getFanspeed()));
|
||||
case CHANNEL_FILTER_LIFE:
|
||||
return new QuantityType<>(reported.getFilterLife(), Units.PERCENT);
|
||||
case CHANNEL_IONIZER:
|
||||
return OnOffType.from(reported.isIonizer());
|
||||
case CHANNEL_UI_LIGHT:
|
||||
return OnOffType.from(reported.isUiLight());
|
||||
case CHANNEL_SAFETY_LOCK:
|
||||
return OnOffType.from(reported.isSafetyLock());
|
||||
case CHANNEL_WORK_MODE:
|
||||
return new StringType(reported.getWorkmode());
|
||||
case CHANNEL_DOOR_STATE:
|
||||
return reported.isDoorOpen() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> refreshProperties() {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
|
||||
final Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getHandler() instanceof ElectroluxApplianceBridgeHandler bridgeHandler) {
|
||||
ApplianceDTO dto = bridgeHandler.getElectroluxApplianceThings().get(config.getSerialNumber());
|
||||
if (dto != null) {
|
||||
var applianceInfo = dto.getApplianceInfo().getApplianceInfo();
|
||||
properties.put(Thing.PROPERTY_VENDOR, applianceInfo.getBrand());
|
||||
properties.put(PROPERTY_COLOUR, applianceInfo.getColour());
|
||||
properties.put(PROPERTY_DEVICE, applianceInfo.getDeviceType());
|
||||
properties.put(Thing.PROPERTY_MODEL_ID, applianceInfo.getModel());
|
||||
properties.put(Thing.PROPERTY_SERIAL_NUMBER, applianceInfo.getSerialNumber());
|
||||
properties.put(Thing.PROPERTY_FIRMWARE_VERSION,
|
||||
((AirPurifierStateDTO) dto.getApplianceState()).getProperties().getReported().getFrmVerNIU());
|
||||
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.handler;
|
||||
|
||||
import static org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBindingConstants.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBridgeConfiguration;
|
||||
import org.openhab.binding.electroluxappliance.internal.api.ElectroluxGroupAPI;
|
||||
import org.openhab.binding.electroluxappliance.internal.discovery.ElectroluxApplianceDiscoveryService;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.ApplianceDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.listener.TokenUpdateListener;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxApplianceBridgeHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxApplianceBridgeHandler extends BaseBridgeHandler implements TokenUpdateListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ElectroluxApplianceBridgeHandler.class);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BRIDGE);
|
||||
|
||||
private int refreshTimeInSeconds = 300;
|
||||
private boolean isCommunicationError = false;
|
||||
|
||||
private final Gson gson;
|
||||
private final HttpClient httpClient;
|
||||
private final Map<String, ApplianceDTO> electroluxApplianceThings = new ConcurrentHashMap<>();
|
||||
|
||||
private @Nullable ElectroluxGroupAPI api;
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
private @Nullable ScheduledFuture<?> instantUpdate;
|
||||
|
||||
public ElectroluxApplianceBridgeHandler(Bridge bridge, HttpClient httpClient, Gson gson) {
|
||||
super(bridge);
|
||||
this.httpClient = httpClient;
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
ElectroluxApplianceBridgeConfiguration config = getConfigAs(ElectroluxApplianceBridgeConfiguration.class);
|
||||
|
||||
refreshTimeInSeconds = config.refresh;
|
||||
|
||||
if (config.apiKey.isBlank() || config.refreshToken.isBlank()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Configuration of API key, access and refresh token is mandatory");
|
||||
} else if (refreshTimeInSeconds < 10) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Refresh time cannot be less than 10!");
|
||||
} else {
|
||||
try {
|
||||
this.api = new ElectroluxGroupAPI(config, gson, httpClient, this);
|
||||
scheduler.execute(() -> {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
startAutomaticRefresh();
|
||||
});
|
||||
} catch (RuntimeException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTokenUpdated(@Nullable String newRefreshToken) {
|
||||
// Create a new configuration object with the updated tokens
|
||||
Configuration configuration = editConfiguration();
|
||||
configuration.put("refreshToken", newRefreshToken);
|
||||
// Update the configuration
|
||||
updateConfiguration(configuration);
|
||||
}
|
||||
|
||||
public Map<String, ApplianceDTO> getElectroluxApplianceThings() {
|
||||
return electroluxApplianceThings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Set.of(ElectroluxApplianceDiscoveryService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopAutomaticRefresh();
|
||||
}
|
||||
|
||||
public @Nullable ElectroluxGroupAPI getElectroluxDeltaAPI() {
|
||||
return api;
|
||||
}
|
||||
|
||||
private boolean refreshAndUpdateStatus() {
|
||||
if (api != null) {
|
||||
if (api.refresh(electroluxApplianceThings, isCommunicationError)) {
|
||||
getThing().getThings().stream().forEach(thing -> {
|
||||
ElectroluxApplianceHandler handler = (ElectroluxApplianceHandler) thing.getHandler();
|
||||
if (handler != null) {
|
||||
handler.update();
|
||||
}
|
||||
});
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
isCommunicationError = false;
|
||||
return true;
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
isCommunicationError = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startAutomaticRefresh() {
|
||||
ScheduledFuture<?> refreshJob = this.refreshJob;
|
||||
if (refreshJob == null || refreshJob.isCancelled()) {
|
||||
this.refreshJob = scheduler.scheduleWithFixedDelay(this::refreshAndUpdateStatus, 0, refreshTimeInSeconds,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopAutomaticRefresh() {
|
||||
ScheduledFuture<?> refreshJob = this.refreshJob;
|
||||
if (refreshJob != null) {
|
||||
refreshJob.cancel(true);
|
||||
this.refreshJob = null;
|
||||
}
|
||||
refreshJob = this.instantUpdate;
|
||||
if (refreshJob != null) {
|
||||
refreshJob.cancel(true);
|
||||
this.refreshJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void updateNow() {
|
||||
Future<?> localRef = instantUpdate;
|
||||
if (localRef == null || localRef.isDone()) {
|
||||
instantUpdate = scheduler.schedule(this::refreshAndUpdateStatus, 0, TimeUnit.SECONDS);
|
||||
} else {
|
||||
logger.debug("Already waiting for scheduled refresh");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("Command received: {} on channelID: {}", command, channelUID);
|
||||
if (CHANNEL_STATUS.equals(channelUID.getId()) || command instanceof RefreshType) {
|
||||
updateNow();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.handler;
|
||||
|
||||
import static org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBindingConstants.CHANNEL_STATUS;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceConfiguration;
|
||||
import org.openhab.binding.electroluxappliance.internal.api.ElectroluxGroupAPI;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.ApplianceDTO;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxApplianceHandler} is
|
||||
*
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class ElectroluxApplianceHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ElectroluxApplianceHandler.class);
|
||||
|
||||
private ElectroluxApplianceConfiguration config = new ElectroluxApplianceConfiguration();
|
||||
|
||||
public ElectroluxApplianceHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("Command received: {} on channelID: {}", command, channelUID);
|
||||
if (CHANNEL_STATUS.equals(channelUID.getId()) || command instanceof RefreshType) {
|
||||
final Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getHandler() instanceof ElectroluxApplianceBridgeHandler bridgeHandler) {
|
||||
bridgeHandler.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(ElectroluxApplianceConfiguration.class);
|
||||
if (config.getSerialNumber().isBlank()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Configuration of Serial Number is mandatory");
|
||||
} else {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
scheduler.execute(() -> {
|
||||
update();
|
||||
Map<String, String> properties = refreshProperties();
|
||||
updateProperties(properties);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
ApplianceDTO dto = getApplianceDTO();
|
||||
if (dto != null) {
|
||||
update(dto);
|
||||
} else {
|
||||
logger.warn("AppliancedDTO is null!");
|
||||
}
|
||||
}
|
||||
|
||||
protected @Nullable ElectroluxGroupAPI getElectroluxGroupAPI() {
|
||||
final Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getHandler() instanceof ElectroluxApplianceBridgeHandler bridgeHandler) {
|
||||
return bridgeHandler.getElectroluxDeltaAPI();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected @Nullable ApplianceDTO getApplianceDTO() {
|
||||
final Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getHandler() instanceof ElectroluxApplianceBridgeHandler bridgeHandler) {
|
||||
return bridgeHandler.getElectroluxApplianceThings().get(config.getSerialNumber());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void update(@Nullable ApplianceDTO dto);
|
||||
|
||||
public abstract Map<String, String> refreshProperties();
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.handler;
|
||||
|
||||
import static org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBindingConstants.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxApplianceHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.electroluxappliance", service = ThingHandlerFactory.class)
|
||||
public class ElectroluxApplianceHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ELECTROLUX_AIR_PURIFIER,
|
||||
THING_TYPE_ELECTROLUX_WASHING_MACHINE, THING_TYPE_BRIDGE);
|
||||
private final Gson gson;
|
||||
private HttpClient httpClient;
|
||||
private final Logger logger = LoggerFactory.getLogger(ElectroluxApplianceHandlerFactory.class);
|
||||
|
||||
@Activate
|
||||
public ElectroluxApplianceHandlerFactory(@Reference HttpClientFactory httpClientFactory) {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
this.gson = new Gson();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_ELECTROLUX_AIR_PURIFIER.equals(thingTypeUID)) {
|
||||
return new ElectroluxAirPurifierHandler(thing);
|
||||
} else if (THING_TYPE_ELECTROLUX_WASHING_MACHINE.equals(thingTypeUID)) {
|
||||
return new ElectroluxWashingMachineHandler(thing);
|
||||
} else if (THING_TYPE_BRIDGE.equals(thingTypeUID)) {
|
||||
return new ElectroluxApplianceBridgeHandler((Bridge) thing, httpClient, gson);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.handler;
|
||||
|
||||
import static org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.electroluxappliance.internal.ElectroluxApplianceConfiguration;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.ApplianceDTO;
|
||||
import org.openhab.binding.electroluxappliance.internal.dto.WashingMachineStateDTO;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link ElectroluxWashingMachineHandler} is responsible for handling commands and status updates for
|
||||
* Electrolux washing machines.
|
||||
*
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ElectroluxWashingMachineHandler extends ElectroluxApplianceHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ElectroluxWashingMachineHandler.class);
|
||||
|
||||
private ElectroluxApplianceConfiguration config = new ElectroluxApplianceConfiguration();
|
||||
|
||||
public ElectroluxWashingMachineHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("Command received: {} on channelID: {}", command, channelUID);
|
||||
if (CHANNEL_STATUS.equals(channelUID.getId()) || command instanceof RefreshType) {
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@Nullable ApplianceDTO dto) {
|
||||
if (dto != null) {
|
||||
// Update all channels from the updated data
|
||||
getThing().getChannels().stream().map(Channel::getUID).filter(channelUID -> isLinked(channelUID))
|
||||
.forEach(channelUID -> {
|
||||
State state = getValue(channelUID.getId(), dto);
|
||||
logger.trace("Channel: {}, State: {}", channelUID, state);
|
||||
updateState(channelUID, state);
|
||||
});
|
||||
if ("Connected".equalsIgnoreCase(dto.getApplianceState().getConnectionState())) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Washing Machine not connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private State getValue(String channelId, ApplianceDTO dto) {
|
||||
var reported = ((WashingMachineStateDTO) dto.getApplianceState()).getProperties().getReported();
|
||||
switch (channelId) {
|
||||
case CHANNEL_DOOR_STATE:
|
||||
return "OPEN".equals(reported.getDoorState()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
|
||||
case CHANNEL_DOOR_LOCK:
|
||||
return "ON".equals(reported.getDoorLock()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
|
||||
case CHANNEL_TIME_TO_START:
|
||||
return new QuantityType<>(reported.getStartTime(), Units.SECOND);
|
||||
case CHANNEL_TIME_TO_END:
|
||||
return new QuantityType<>(reported.getTimeToEnd(), Units.SECOND);
|
||||
case CHANNEL_APPLIANCE_UI_SW_VERSION:
|
||||
return new StringType(reported.getApplianceUiSwVersion());
|
||||
case CHANNEL_OPTISENSE_RESULT:
|
||||
return new StringType(Integer.toString(reported.getFCMiscellaneousState().getOptisenseResult()));
|
||||
case CHANNEL_DETERGENT_EXTRA_DOSAGE:
|
||||
return new StringType(Integer.toString(reported.getFCMiscellaneousState().getDetergentExtradosage()));
|
||||
case CHANNEL_SOFTENER_EXTRA_DOSAGE:
|
||||
return new StringType(Integer.toString(reported.getFCMiscellaneousState().getSoftenerExtradosage()));
|
||||
case CHANNEL_WATER_USAGE:
|
||||
return new QuantityType<>(reported.getFCMiscellaneousState().getWaterUsage(), Units.LITRE);
|
||||
case CHANNEL_TOTAL_WASH_CYCLES_COUNT:
|
||||
return new StringType(Integer.toString(reported.getTotalWashCyclesCount()));
|
||||
case CHANNEL_CYCLE_PHASE:
|
||||
return new StringType(reported.getCyclePhase());
|
||||
case CHANNEL_APPLIANCE_TOTAL_WORKING_TIME:
|
||||
return new StringType(Integer.toString(reported.getApplianceTotalWorkingTime()));
|
||||
case CHANNEL_APPLIANCE_STATE:
|
||||
return new StringType(reported.getApplianceState());
|
||||
case CHANNEL_APPLIANCE_MODE:
|
||||
return new StringType(reported.getApplianceMode());
|
||||
case CHANNEL_ANALOG_TEMPERATURE:
|
||||
return new StringType(reported.getUserSelections().getAnalogTemperature());
|
||||
case CHANNEL_ANALOG_SPIN_SPEED:
|
||||
return new StringType(reported.getUserSelections().getAnalogSpinSpeed());
|
||||
case CHANNEL_STEAM_VALUE:
|
||||
return new StringType(reported.getUserSelections().getSteamValue());
|
||||
case CHANNEL_PROGRAMS_ORDER:
|
||||
return new StringType(reported.getUserSelections().getProgramUID());
|
||||
|
||||
}
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> refreshProperties() {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
final Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getHandler() instanceof ElectroluxApplianceBridgeHandler bridgeHandler) {
|
||||
ApplianceDTO dto = bridgeHandler.getElectroluxApplianceThings().get(config.getSerialNumber());
|
||||
if (dto != null) {
|
||||
var applianceInfo = dto.getApplianceInfo().getApplianceInfo();
|
||||
properties.put(Thing.PROPERTY_VENDOR, applianceInfo.getBrand());
|
||||
properties.put(PROPERTY_COLOUR, applianceInfo.getColour());
|
||||
properties.put(PROPERTY_DEVICE, applianceInfo.getDeviceType());
|
||||
properties.put(Thing.PROPERTY_MODEL_ID, applianceInfo.getModel());
|
||||
properties.put(Thing.PROPERTY_SERIAL_NUMBER, applianceInfo.getSerialNumber());
|
||||
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, ((WashingMachineStateDTO) dto.getApplianceState())
|
||||
.getProperties().getReported().getNetworkInterface().getSwVersion());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.binding.electroluxappliance.internal.listener;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link TokenUpdateListener} callback interface for notifying about token updates
|
||||
*
|
||||
* @author Jan Gustafsson - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface TokenUpdateListener {
|
||||
/**
|
||||
* Called when the access token and refresh token are updated.
|
||||
*
|
||||
* @param newAccessToken the new access token
|
||||
* @param newRefreshToken the new refresh token
|
||||
*/
|
||||
void onTokenUpdated(String newRefreshToken);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="electroluxappliance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>Electrolux Appliances Binding</name>
|
||||
<description>This is the binding for Electrolux Appliances.</description>
|
||||
<connection>cloud</connection>
|
||||
|
||||
</addon:addon>
|
@ -0,0 +1,171 @@
|
||||
# add-on
|
||||
|
||||
addon.electroluxappliance.name = Electrolux Appliances Binding
|
||||
addon.electroluxappliance.description = This is the binding for Electrolux Appliances.
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.electroluxappliance.air-purifier.label = Air Purifier
|
||||
thing-type.electroluxappliance.air-purifier.description = This thing represents the Electrolux Air Purifier.
|
||||
thing-type.electroluxappliance.api.label = Electrolux Group API
|
||||
thing-type.electroluxappliance.api.description = This bridge represents the web API connector.
|
||||
thing-type.electroluxappliance.washing-machine.label = Washing Machine
|
||||
thing-type.electroluxappliance.washing-machine.description = This thing represents the Electrolux Washing Machine.
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.electroluxappliance.air-purifier.serialNumber.label = Serial Number
|
||||
thing-type.config.electroluxappliance.air-purifier.serialNumber.description = The appliance serial number.
|
||||
thing-type.config.electroluxappliance.api.apiKey.label = API Key
|
||||
thing-type.config.electroluxappliance.api.apiKey.description = Your personal API key.
|
||||
thing-type.config.electroluxappliance.api.refresh.label = Refresh Interval
|
||||
thing-type.config.electroluxappliance.api.refresh.description = Specifies the refresh interval in seconds.
|
||||
thing-type.config.electroluxappliance.api.refreshToken.label = Refresh Token
|
||||
thing-type.config.electroluxappliance.api.refreshToken.description = Your personal Refresh Token.
|
||||
thing-type.config.electroluxappliance.washing-machine.serialNumber.label = Serial Number
|
||||
thing-type.config.electroluxappliance.washing-machine.serialNumber.description = The appliance serial number.
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.electroluxappliance.analog-spin-speed.label = Spin Speed
|
||||
channel-type.electroluxappliance.analog-spin-speed.description = The spin speed.
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.DISABLED = Disabled
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.0_RPM = 0 rpm
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.400_RPM = 400 rpm
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.600_RPM = 600 rpm
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.800_RPM = 800 rpm
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.1000_RPM = 1000 rpm
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.1200_RPM = 1200 rpm
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.1400_RPM = 1400 rpm
|
||||
channel-type.electroluxappliance.analog-spin-speed.state.option.1600_RPM = 1600 rpm
|
||||
channel-type.electroluxappliance.analog-temperature.label = Washing Temperature
|
||||
channel-type.electroluxappliance.analog-temperature.description = The user configured washing temperature.
|
||||
channel-type.electroluxappliance.analog-temperature.state.option.20_CELSIUS = 20°C
|
||||
channel-type.electroluxappliance.analog-temperature.state.option.30_CELSIUS = 30°C
|
||||
channel-type.electroluxappliance.analog-temperature.state.option.40_CELSIUS = 40°C
|
||||
channel-type.electroluxappliance.analog-temperature.state.option.50_CELSIUS = 50°C
|
||||
channel-type.electroluxappliance.analog-temperature.state.option.60_CELSIUS = 60°C
|
||||
channel-type.electroluxappliance.analog-temperature.state.option.90_CELSIUS = 90°C
|
||||
channel-type.electroluxappliance.analog-temperature.state.option.COLD = Cold
|
||||
channel-type.electroluxappliance.appliance-mode.label = Appliance Mode
|
||||
channel-type.electroluxappliance.appliance-mode.description = The appliance mode.
|
||||
channel-type.electroluxappliance.appliance-mode.state.option.DEMO = Demo
|
||||
channel-type.electroluxappliance.appliance-mode.state.option.DIAGNOSTIC = Diagnostic
|
||||
channel-type.electroluxappliance.appliance-mode.state.option.NORMAL = Normal
|
||||
channel-type.electroluxappliance.appliance-mode.state.option.SERVICE = Service
|
||||
channel-type.electroluxappliance.appliance-state.label = Appliance State
|
||||
channel-type.electroluxappliance.appliance-state.description = The appliance state.
|
||||
channel-type.electroluxappliance.appliance-state.state.option.ALARM = Alarm
|
||||
channel-type.electroluxappliance.appliance-state.state.option.DELAYED_START = Delayed start
|
||||
channel-type.electroluxappliance.appliance-state.state.option.END_OF_CYCLE = End of cycle
|
||||
channel-type.electroluxappliance.appliance-state.state.option.IDLE = Idle
|
||||
channel-type.electroluxappliance.appliance-state.state.option.OFF = Off
|
||||
channel-type.electroluxappliance.appliance-state.state.option.PAUSED = Paused
|
||||
channel-type.electroluxappliance.appliance-state.state.option.READY_TO_START = Ready to start
|
||||
channel-type.electroluxappliance.appliance-state.state.option.RUNNING = Running
|
||||
channel-type.electroluxappliance.appliance-total-working-time.label = Appliance Total Working Time
|
||||
channel-type.electroluxappliance.appliance-total-working-time.description = The appliance total working time.
|
||||
channel-type.electroluxappliance.appliance-ui-sw-version.label = Appliance UI SW Version
|
||||
channel-type.electroluxappliance.appliance-ui-sw-version.description = The appliance UI SW version.
|
||||
channel-type.electroluxappliance.co2.label = CO2
|
||||
channel-type.electroluxappliance.co2.description = The measured CarbonDioxide.
|
||||
channel-type.electroluxappliance.cycle-phase.label = Cycle Phase
|
||||
channel-type.electroluxappliance.cycle-phase.description = The washing cycle phase.
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.UNAVAILABLE = Unavailable
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.ANTICREASE = Anicrease
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.DRAIN = Drain
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.DRY = Dry
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.PREWASH = Prewash
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.RINSE = Rinse
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.SPIN = Spin
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.STEAM = Steam
|
||||
channel-type.electroluxappliance.cycle-phase.state.option.WASH = Wash
|
||||
channel-type.electroluxappliance.detergent-extradosage.label = Detergent Extra Dosage
|
||||
channel-type.electroluxappliance.detergent-extradosage.description = The detergent extra dosage.
|
||||
channel-type.electroluxappliance.door-lock.label = Door Lock
|
||||
channel-type.electroluxappliance.door-lock.description = The door lock status Open/Closed.
|
||||
channel-type.electroluxappliance.door-state.label = Door State
|
||||
channel-type.electroluxappliance.door-state.description = The door status Open/Closed.
|
||||
channel-type.electroluxappliance.fan-speed.label = Fan Speed Setting
|
||||
channel-type.electroluxappliance.fan-speed.description = The fan speed setting.
|
||||
channel-type.electroluxappliance.fan-speed.state.option.1 = Level 1
|
||||
channel-type.electroluxappliance.fan-speed.state.option.2 = Level 2
|
||||
channel-type.electroluxappliance.fan-speed.state.option.3 = Level 3
|
||||
channel-type.electroluxappliance.fan-speed.state.option.4 = Level 4
|
||||
channel-type.electroluxappliance.fan-speed.state.option.5 = Level 5
|
||||
channel-type.electroluxappliance.fan-speed.state.option.6 = Level 6
|
||||
channel-type.electroluxappliance.fan-speed.state.option.7 = Level 7
|
||||
channel-type.electroluxappliance.fan-speed.state.option.8 = Level 8
|
||||
channel-type.electroluxappliance.fan-speed.state.option.9 = Level 9
|
||||
channel-type.electroluxappliance.filter-life.label = Remaining Filter Life
|
||||
channel-type.electroluxappliance.filter-life.description = The remaining filter life indication in percent.
|
||||
channel-type.electroluxappliance.humidity.label = Humidity
|
||||
channel-type.electroluxappliance.humidity.description = The measured humidity.
|
||||
channel-type.electroluxappliance.ionizer.label = Ionizer Status
|
||||
channel-type.electroluxappliance.ionizer.description = The ionizer status On/Off.
|
||||
channel-type.electroluxappliance.optisense-result.label = Optisense Result
|
||||
channel-type.electroluxappliance.optisense-result.description = The optisense result.
|
||||
channel-type.electroluxappliance.pm1.label = PM1
|
||||
channel-type.electroluxappliance.pm1.description = The Particulate Matter 1 (0.001mm).
|
||||
channel-type.electroluxappliance.pm10.label = PM10
|
||||
channel-type.electroluxappliance.pm10.description = The Particulate Matter 10 (0.01mm).
|
||||
channel-type.electroluxappliance.pm2_5.label = PM2.5
|
||||
channel-type.electroluxappliance.pm2_5.description = The Particulate Matter 2.5 (0.0025mm).
|
||||
channel-type.electroluxappliance.programs-order.label = Programs Order
|
||||
channel-type.electroluxappliance.programs-order.description = The user configured washing program.
|
||||
channel-type.electroluxappliance.programs-order.state.option.MACHINE_SETTINGS_HIDDEN_TEST = Machine settings hidden test
|
||||
channel-type.electroluxappliance.programs-order.state.option.COTTON_PR_ECO40-60 = Cotton Eco 40°C-60°C
|
||||
channel-type.electroluxappliance.programs-order.state.option.COTTON_PR_COTTONS = Cotton
|
||||
channel-type.electroluxappliance.programs-order.state.option.SYNTHETIC_PR_SYNTHETICS = Synthetics
|
||||
channel-type.electroluxappliance.programs-order.state.option.DELICATE_PR_DELICATES = Delicates
|
||||
channel-type.electroluxappliance.programs-order.state.option.WOOL_PR_WOOL_SILK = Wool Silk
|
||||
channel-type.electroluxappliance.programs-order.state.option.STEAM_REFRESH_PR_STEAMFRESHSCENT = Steam fresh cent
|
||||
channel-type.electroluxappliance.programs-order.state.option.SPIN_PR_DRAIN_SPIN = Drain spin
|
||||
channel-type.electroluxappliance.programs-order.state.option.SOFTENER_PR_RINSE = Softener rinse
|
||||
channel-type.electroluxappliance.programs-order.state.option.QUICK_20_MIN_PR_RAPID20MIN = Rapid 20min
|
||||
channel-type.electroluxappliance.programs-order.state.option.SPORT_JACKETS_PR_OUTDOOR = Sport jackets outdoor
|
||||
channel-type.electroluxappliance.programs-order.state.option.SYNTHETIC_PR_SPORT = Synthetic sport
|
||||
channel-type.electroluxappliance.programs-order.state.option.DENIM_PR_DENIM = Denim
|
||||
channel-type.electroluxappliance.programs-order.state.option.BLANKET_PR_DUVET = Blanket duvet
|
||||
channel-type.electroluxappliance.programs-order.state.option.SANITISE60_PR_ANTIALLERGYVAPOUR = Anti allergy vapour
|
||||
channel-type.electroluxappliance.programs-order.state.option.COTTON_PR_BUSINESSSHIRTS = Cotton business shirts
|
||||
channel-type.electroluxappliance.programs-order.state.option.DRUM_CLEAN_PR_MACHINECLEAN = Drum machine clean
|
||||
channel-type.electroluxappliance.programs-order.state.option.STEAM_DEWRINKLER_PR_STEAMCASHMERE = Steam cashmere
|
||||
channel-type.electroluxappliance.programs-order.state.option.SYNTHETIC_PR_BEDLINEN = Synthetic bedlinen
|
||||
channel-type.electroluxappliance.programs-order.state.option.COTTON_PR_TOWELS = Cotton towels
|
||||
channel-type.electroluxappliance.programs-order.state.option.DELICATE_PR_CURTAINS = Delicate curtains
|
||||
channel-type.electroluxappliance.programs-order.state.option.SYNTHETIC_PR_FLEECE = Synthetic fleece
|
||||
channel-type.electroluxappliance.programs-order.state.option.COTTON_PR_WORKINGCLOTHES = Cotton working clothes
|
||||
channel-type.electroluxappliance.programs-order.state.option.SYNTHETIC_PR_MICROFIBRE = Synthetic microfibre
|
||||
channel-type.electroluxappliance.programs-order.state.option.DELICATE_PR_BABY = Delicate baby
|
||||
channel-type.electroluxappliance.safety-lock.label = Safety Lock
|
||||
channel-type.electroluxappliance.safety-lock.description = The safety lock status.
|
||||
channel-type.electroluxappliance.softener-extradosage.label = Softener Extra Dosage
|
||||
channel-type.electroluxappliance.softener-extradosage.description = The softener extra dosage.
|
||||
channel-type.electroluxappliance.status.label = Fetch Current Status
|
||||
channel-type.electroluxappliance.status.description = Used to fetch latest status from API.
|
||||
channel-type.electroluxappliance.steam-value.label = Steam Value
|
||||
channel-type.electroluxappliance.steam-value.description = The user configured steam value.
|
||||
channel-type.electroluxappliance.steam-value.state.option.STEAM_OFF = Steam off
|
||||
channel-type.electroluxappliance.steam-value.state.option.STEAM_MIN = Steam minumum
|
||||
channel-type.electroluxappliance.steam-value.state.option.STEAM_MED = Steam medium
|
||||
channel-type.electroluxappliance.steam-value.state.option.STEAM_MAX = Steam max
|
||||
channel-type.electroluxappliance.temperature.label = Temperature
|
||||
channel-type.electroluxappliance.temperature.description = The measured temperature.
|
||||
channel-type.electroluxappliance.time-to-end.label = Time To End
|
||||
channel-type.electroluxappliance.time-to-end.description = The time remaining until the program will end.
|
||||
channel-type.electroluxappliance.time-to-start.label = Time To Delayed Start
|
||||
channel-type.electroluxappliance.time-to-start.description = The time remaining until the delayed start.
|
||||
channel-type.electroluxappliance.total-wash-cycles-count.label = Total Wash Cycles Count
|
||||
channel-type.electroluxappliance.total-wash-cycles-count.description = The total wash cycles count.
|
||||
channel-type.electroluxappliance.tvoc.label = TVOC
|
||||
channel-type.electroluxappliance.tvoc.description = The total Volatile Organic Compounds.
|
||||
channel-type.electroluxappliance.ui-light.label = UI Light
|
||||
channel-type.electroluxappliance.ui-light.description = The air quality light status indication.
|
||||
channel-type.electroluxappliance.water-usage.label = Water Usage
|
||||
channel-type.electroluxappliance.water-usage.description = The water usage in litres.
|
||||
channel-type.electroluxappliance.work-mode.label = Work Mode Setting
|
||||
channel-type.electroluxappliance.work-mode.description = The work mode setting.
|
||||
channel-type.electroluxappliance.work-mode.state.option.PowerOff = Power Off
|
||||
channel-type.electroluxappliance.work-mode.state.option.Auto = Automatic
|
||||
channel-type.electroluxappliance.work-mode.state.option.Manual = Manual
|
@ -0,0 +1,450 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="electroluxappliance"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<bridge-type id="api">
|
||||
<label>Electrolux Group API</label>
|
||||
<description>This bridge represents the web API connector.</description>
|
||||
|
||||
<properties>
|
||||
<property name="vendor">Electrolux</property>
|
||||
</properties>
|
||||
|
||||
<config-description>
|
||||
<parameter name="apiKey" type="text" required="true">
|
||||
<label>API Key</label>
|
||||
<description>Your personal API key.</description>
|
||||
</parameter>
|
||||
<parameter name="refreshToken" type="text" required="true">
|
||||
<label>Refresh Token</label>
|
||||
<description>Your personal Refresh Token.</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="10" unit="s">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval in seconds.</description>
|
||||
<default>300</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="air-purifier">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="api"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Air Purifier</label>
|
||||
<description>This thing represents the Electrolux Air Purifier.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="humidity" typeId="humidity"/>
|
||||
<channel id="tvoc" typeId="tvoc"/>
|
||||
<channel id="pm1" typeId="pm1"/>
|
||||
<channel id="pm2_5" typeId="pm2_5"/>
|
||||
<channel id="pm10" typeId="pm10"/>
|
||||
<channel id="co2" typeId="co2"/>
|
||||
<channel id="filter-life" typeId="filter-life"/>
|
||||
<channel id="door-state" typeId="door-state"/>
|
||||
<channel id="fan-speed" typeId="fan-speed"/>
|
||||
<channel id="work-mode" typeId="work-mode"/>
|
||||
<channel id="ionizer" typeId="ionizer"/>
|
||||
<channel id="ui-light" typeId="ui-light"/>
|
||||
<channel id="safety-lock" typeId="safety-lock"/>
|
||||
<channel id="status" typeId="status"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="vendor">Electrolux</property>
|
||||
</properties>
|
||||
|
||||
<representation-property>serialNumber</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="serialNumber" type="text" required="true">
|
||||
<label>Serial Number</label>
|
||||
<description>The appliance serial number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="washing-machine">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="api"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Washing Machine</label>
|
||||
<description>This thing represents the Electrolux Washing Machine.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="door-state" typeId="door-state"/>
|
||||
<channel id="door-lock" typeId="door-lock"/>
|
||||
<channel id="time-to-start" typeId="time-to-start"/>
|
||||
<channel id="time-to-end" typeId="time-to-end"/>
|
||||
<channel id="cycle-phase" typeId="cycle-phase"/>
|
||||
<channel id="analog-temperature" typeId="analog-temperature"/>
|
||||
<channel id="analog-spin-speed" typeId="analog-spin-speed"/>
|
||||
<channel id="steam-value" typeId="steam-value"/>
|
||||
<channel id="programs-order" typeId="programs-order"/>
|
||||
<channel id="appliance-state" typeId="appliance-state"/>
|
||||
<channel id="appliance-mode" typeId="appliance-mode"/>
|
||||
<channel id="appliance-ui-sw-version" typeId="appliance-ui-sw-version"/>
|
||||
<channel id="appliance-total-working-time" typeId="appliance-total-working-time"/>
|
||||
<channel id="optisense-result" typeId="optisense-result"/>
|
||||
<channel id="detergent-extradosage" typeId="detergent-extradosage"/>
|
||||
<channel id="softener-extradosage" typeId="softener-extradosage"/>
|
||||
<channel id="water-usage" typeId="water-usage"/>
|
||||
<channel id="total-wash-cycles-count" typeId="total-wash-cycles-count"/>
|
||||
<channel id="status" typeId="status"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="vendor">Electrolux</property>
|
||||
</properties>
|
||||
|
||||
<representation-property>serialNumber</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="serialNumber" type="text" required="true">
|
||||
<label>Serial Number</label>
|
||||
<description>The appliance serial number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
|
||||
<channel-type id="status">
|
||||
<item-type>String</item-type>
|
||||
<label>Fetch Current Status</label>
|
||||
<description>Used to fetch latest status from API.</description>
|
||||
<state readOnly="true" pattern="%s"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>The measured temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%">
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="humidity">
|
||||
<item-type unitHint="%">Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>The measured humidity.</description>
|
||||
<category>Humidity</category>
|
||||
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tvoc">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>TVOC</label>
|
||||
<description>The total Volatile Organic Compounds.</description>
|
||||
<state readOnly="true" pattern="%d ppb"/>
|
||||
</channel-type>
|
||||
|
||||
|
||||
<channel-type id="pm1">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>PM1</label>
|
||||
<description>The Particulate Matter 1 (0.001mm).</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm2_5">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>PM2.5</label>
|
||||
<description>The Particulate Matter 2.5 (0.0025mm).</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm10">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>PM10</label>
|
||||
<description>The Particulate Matter 10 (0.01mm).</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="co2">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>CO2</label>
|
||||
<description>The measured CarbonDioxide.</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="filter-life">
|
||||
<item-type unitHint="%">Number:Dimensionless</item-type>
|
||||
<label>Remaining Filter Life</label>
|
||||
<description>The remaining filter life indication in percent.</description>
|
||||
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="fan-speed">
|
||||
<item-type>Number</item-type>
|
||||
<label>Fan Speed Setting</label>
|
||||
<description>The fan speed setting.</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="1">Level 1</option>
|
||||
<option value="2">Level 2</option>
|
||||
<option value="3">Level 3</option>
|
||||
<option value="4">Level 4</option>
|
||||
<option value="5">Level 5</option>
|
||||
<option value="6">Level 6</option>
|
||||
<option value="7">Level 7</option>
|
||||
<option value="8">Level 8</option>
|
||||
<option value="9">Level 9</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="work-mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Work Mode Setting</label>
|
||||
<description>The work mode setting.</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="PowerOff">Power Off</option>
|
||||
<option value="Auto">Automatic</option>
|
||||
<option value="Manual">Manual</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ionizer">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Ionizer Status</label>
|
||||
<description>The ionizer status On/Off.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ui-light">
|
||||
<item-type>Switch</item-type>
|
||||
<label>UI Light</label>
|
||||
<description>The air quality light status indication.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="safety-lock">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Safety Lock</label>
|
||||
<description>The safety lock status.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="door-lock">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Door Lock</label>
|
||||
<description>The door lock status Open/Closed.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="door-state">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Door State</label>
|
||||
<description>The door status Open/Closed.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="time-to-start">
|
||||
<item-type unitHint="s">Number:Time</item-type>
|
||||
<label>Time To Delayed Start</label>
|
||||
<description>The time remaining until the delayed start.</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="time-to-end">
|
||||
<item-type unitHint="s">Number:Time</item-type>
|
||||
<label>Time To End</label>
|
||||
<description>The time remaining until the program will end.</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="appliance-ui-sw-version">
|
||||
<item-type>String</item-type>
|
||||
<label>Appliance UI SW Version</label>
|
||||
<description>The appliance UI SW version.</description>
|
||||
<state readOnly="true" pattern="%s"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="appliance-total-working-time">
|
||||
<item-type unitHint="s">Number:Time</item-type>
|
||||
<label>Appliance Total Working Time</label>
|
||||
<description>The appliance total working time.</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="optisense-result">
|
||||
<item-type>Number</item-type>
|
||||
<label>Optisense Result</label>
|
||||
<description>The optisense result.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="detergent-extradosage">
|
||||
<item-type>Number</item-type>
|
||||
<label>Detergent Extra Dosage</label>
|
||||
<description>The detergent extra dosage.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="softener-extradosage">
|
||||
<item-type>Number</item-type>
|
||||
<label>Softener Extra Dosage</label>
|
||||
<description>The softener extra dosage.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="water-usage">
|
||||
<item-type unitHint="l">Number:Volume</item-type>
|
||||
<label>Water Usage</label>
|
||||
<description>The water usage in litres.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="total-wash-cycles-count">
|
||||
<item-type>Number</item-type>
|
||||
<label>Total Wash Cycles Count</label>
|
||||
<description>The total wash cycles count.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="cycle-phase">
|
||||
<item-type>String</item-type>
|
||||
<label>Cycle Phase</label>
|
||||
<description>The washing cycle phase.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="UNAVAILABLE">Unavailable</option>
|
||||
<option value="ANTICREASE">Anicrease</option>
|
||||
<option value="DRAIN">Drain</option>
|
||||
<option value="DRY">Dry</option>
|
||||
<option value="PREWASH">Prewash</option>
|
||||
<option value="RINSE">Rinse</option>
|
||||
<option value="SPIN">Spin</option>
|
||||
<option value="STEAM">Steam</option>
|
||||
<option value="WASH">Wash</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="appliance-state">
|
||||
<item-type>String</item-type>
|
||||
<label>Appliance State</label>
|
||||
<description>The appliance state.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ALARM">Alarm</option>
|
||||
<option value="DELAYED_START">Delayed start</option>
|
||||
<option value="END_OF_CYCLE">End of cycle</option>
|
||||
<option value="IDLE">Idle</option>
|
||||
<option value="OFF">Off</option>
|
||||
<option value="PAUSED">Paused</option>
|
||||
<option value="READY_TO_START">Ready to start</option>
|
||||
<option value="RUNNING">Running</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="appliance-mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Appliance Mode</label>
|
||||
<description>The appliance mode.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="DEMO">Demo</option>
|
||||
<option value="DIAGNOSTIC">Diagnostic</option>
|
||||
<option value="NORMAL">Normal</option>
|
||||
<option value="SERVICE">Service</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="analog-temperature">
|
||||
<item-type>String</item-type>
|
||||
<label>Washing Temperature </label>
|
||||
<description>The user configured washing temperature.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="20_CELSIUS">20°C</option>
|
||||
<option value="30_CELSIUS">30°C</option>
|
||||
<option value="40_CELSIUS">40°C</option>
|
||||
<option value="50_CELSIUS">50°C</option>
|
||||
<option value="60_CELSIUS">60°C</option>
|
||||
<option value="90_CELSIUS">90°C</option>
|
||||
<option value="COLD">Cold</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
|
||||
<channel-type id="analog-spin-speed">
|
||||
<item-type>String</item-type>
|
||||
<label>Spin Speed</label>
|
||||
<description>The spin speed.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="DISABLED">Disabled</option>
|
||||
<option value="0_RPM">0 rpm</option>
|
||||
<option value="400_RPM">400 rpm</option>
|
||||
<option value="600_RPM">600 rpm</option>
|
||||
<option value="800_RPM">800 rpm</option>
|
||||
<option value="1000_RPM">1000 rpm</option>
|
||||
<option value="1200_RPM">1200 rpm</option>
|
||||
<option value="1400_RPM">1400 rpm</option>
|
||||
<option value="1600_RPM">1600 rpm</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="steam-value">
|
||||
<item-type>String</item-type>
|
||||
<label>Steam Value</label>
|
||||
<description>The user configured steam value.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="STEAM_OFF">Steam off</option>
|
||||
<option value="STEAM_MIN">Steam minumum</option>
|
||||
<option value="STEAM_MED">Steam medium</option>
|
||||
<option value="STEAM_MAX">Steam max</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="programs-order">
|
||||
<item-type>String</item-type>
|
||||
<label>Programs Order</label>
|
||||
<description>The user configured washing program.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="MACHINE_SETTINGS_HIDDEN_TEST">Machine settings hidden test</option>
|
||||
<option value="COTTON_PR_ECO40-60">Cotton Eco 40°C-60°C</option>
|
||||
<option value="COTTON_PR_COTTONS">Cotton</option>
|
||||
<option value="SYNTHETIC_PR_SYNTHETICS">Synthetics</option>
|
||||
<option value="DELICATE_PR_DELICATES">Delicates</option>
|
||||
<option value="WOOL_PR_WOOL_SILK">Wool Silk</option>
|
||||
<option value="STEAM_REFRESH_PR_STEAMFRESHSCENT">Steam fresh cent</option>
|
||||
<option value="SPIN_PR_DRAIN_SPIN">Drain spin</option>
|
||||
<option value="SOFTENER_PR_RINSE">Softener rinse</option>
|
||||
<option value="QUICK_20_MIN_PR_RAPID20MIN">Rapid 20min</option>
|
||||
<option value="SPORT_JACKETS_PR_OUTDOOR">Sport jackets outdoor</option>
|
||||
<option value="SYNTHETIC_PR_SPORT">Synthetic sport</option>
|
||||
<option value="DENIM_PR_DENIM">Denim</option>
|
||||
<option value="BLANKET_PR_DUVET">Blanket duvet</option>
|
||||
<option value="SANITISE60_PR_ANTIALLERGYVAPOUR">Anti allergy vapour</option>
|
||||
<option value="COTTON_PR_BUSINESSSHIRTS">Cotton business shirts</option>
|
||||
<option value="DRUM_CLEAN_PR_MACHINECLEAN">Drum machine clean</option>
|
||||
<option value="STEAM_DEWRINKLER_PR_STEAMCASHMERE">Steam cashmere</option>
|
||||
<option value="SYNTHETIC_PR_BEDLINEN">Synthetic bedlinen</option>
|
||||
<option value="COTTON_PR_TOWELS">Cotton towels</option>
|
||||
<option value="DELICATE_PR_CURTAINS">Delicate curtains</option>
|
||||
<option value="SYNTHETIC_PR_FLEECE">Synthetic fleece</option>
|
||||
<option value="COTTON_PR_WORKINGCLOTHES">Cotton working clothes</option>
|
||||
<option value="SYNTHETIC_PR_MICROFIBRE">Synthetic microfibre</option>
|
||||
<option value="DELICATE_PR_BABY">Delicate baby</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -130,6 +130,7 @@
|
||||
<module>org.openhab.binding.ecovacs</module>
|
||||
<module>org.openhab.binding.ecowatt</module>
|
||||
<module>org.openhab.binding.ekey</module>
|
||||
<module>org.openhab.binding.electroluxappliance</module>
|
||||
<module>org.openhab.binding.elerotransmitterstick</module>
|
||||
<module>org.openhab.binding.elroconnects</module>
|
||||
<module>org.openhab.binding.emotiva</module>
|
||||
|
Loading…
Reference in New Issue
Block a user