Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2010-2025 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.hue.internal.api.dto.clip2;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.MuteType;

/**
* DTO for mute state of a sound.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class Mute {
private @Nullable MuteType mute;

public @Nullable MuteType getMute() {
return this.mute;
}

public Mute setMute(MuteType muteType) {
this.mute = muteType;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.openhab.binding.hue.internal.api.dto.clip2.enums.SceneRecallAction;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.SmartSceneRecallAction;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.SmartSceneState;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.SoftwareUpdateStatusType;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.TamperStateType;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.ZigbeeStatus;
import org.openhab.binding.hue.internal.exceptions.DTOPresentButEmptyException;
Expand All @@ -52,6 +53,7 @@
import org.openhab.core.util.ColorUtil;
import org.openhab.core.util.ColorUtil.Gamut;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
Expand All @@ -68,6 +70,7 @@
public class Resource {

public static final MathContext PERCENT_MATH_CONTEXT = new MathContext(4, RoundingMode.HALF_UP);
private static final Gson GSON = new Gson();

/**
* The SSE event mechanism sends resources in a sparse (skeleton) format that only includes state fields whose
Expand Down Expand Up @@ -97,7 +100,7 @@ public class Resource {
private @Nullable Dimming dimming;
private @Nullable @SerializedName("color_temperature") ColorTemperature colorTemperature;
private @Nullable ColorXy color;
private @Nullable Alerts alert;
private @Nullable JsonElement alert;
private @Nullable Effects effects;
private @Nullable @SerializedName("timed_effects") TimedEffects timedEffects;
private @Nullable ResourceReference group;
Expand All @@ -117,6 +120,9 @@ public class Resource {
private @Nullable @SerializedName("tamper_reports") List<TamperReport> tamperReports;
private @Nullable JsonElement state;
private @Nullable @SerializedName("script_id") String scriptId;
private @Nullable Sound alarm;
private @Nullable Sound chime;
private @Nullable Mute mute;

/**
* Constructor
Expand Down Expand Up @@ -171,12 +177,22 @@ public boolean hasHSBField() {
return actions;
}

/**
* Get the alerts setting. We need to disambiguate between an alert setting and an alerts setting, because
* both are represented by the same 'alert' JSON element. If the JSON element contains a 'status' field it is
* an alert setting, if it contains an 'action' or 'action_values' field it is an alerts setting.
*/
public @Nullable Alerts getAlerts() {
return alert;
JsonElement alert = this.alert;
if (Objects.nonNull(alert) && alert.isJsonObject() && (alert.getAsJsonObject().get("action") != null
|| alert.getAsJsonObject().get("action_values") != null)) {
return GSON.fromJson(alert, Alerts.class);
}
return null;
}

public State getAlertState() {
Alerts alerts = this.alert;
Alerts alerts = getAlerts();
if (Objects.nonNull(alerts)) {
if (!alerts.getActionValues().isEmpty()) {
ActionType alertType = alerts.getAction();
Expand Down Expand Up @@ -695,7 +711,9 @@ public State getSceneState() {

/**
* Check if the smart scene resource contains a 'state' element. If such an element is present, returns a Boolean
* whose value depends on the value of that element, or null if it is not.
* whose value depends on the value of that element, or null if it is not. Disambiguate between a software update
* status and a smart scene state, because both are represented by the 'state' JSON element. If the resource type
* is 'device_software_update' it is a software update status, if it is 'smart_scene' it is a smart scene state.
*
* @return true, false, or null.
*/
Expand Down Expand Up @@ -827,8 +845,12 @@ public boolean hasName() {
return Objects.nonNull(metaData) && Objects.nonNull(metaData.getName());
}

/**
* Set the alerts parameter. Note: this method sets the 'alert' JSON element. The 'alert' JSON element is used for
* both alert and alerts settings, so this method should only be used when setting an alerts element.
*/
public Resource setAlerts(Alerts alert) {
this.alert = alert;
this.alert = GSON.toJsonTree(alert);
return this;
}

Expand Down Expand Up @@ -961,4 +983,95 @@ public String toString() {
return String.format("id:%s, type:%s", Objects.nonNull(id) ? id : "?" + " ".repeat(35),
getType().name().toLowerCase());
}

/**
* Get the speaker alarm sound.
*/
public @Nullable Sound getAlarm() {
return alarm;
}

/**
* Get the speaker alert sound. We need to disambiguate between an alert setting and an alerts setting, because
* both are represented by the same 'alert' JSON element. If the JSON element contains a 'status' field it is
* an alert setting, if it contains an 'action' or 'action_values' field it is an alerts setting.
*/
public @Nullable Sound getAlert() {
JsonElement alert = this.alert;
if (Objects.nonNull(alert) && alert.isJsonObject() && alert.getAsJsonObject().get("status") != null) {
return GSON.fromJson(alert, Sound.class);
}
return null;
}

/**
* Get the speaker chime sound.
*/
public @Nullable Sound getChime() {
return chime;
}

/**
* Get the speaker mute state.
*/
public @Nullable Mute getMute() {
return mute;
}

/**
* Get the software update status if any. Disambiguate between a software update status and a smart scene state,
* because both are represented by the 'state' JSON element. If the resource type is 'device_software_update' it
* is a software update status, if it is 'smart_scene' it is a smart scene state.
*/
public @Nullable SoftwareUpdateStatusType getSoftwareUpdateStatus() {
if (ResourceType.DEVICE_SOFTWARE_UPDATE == getType() && (state instanceof JsonPrimitive statePrimitive)) {
String state = statePrimitive.getAsString();
if (Objects.nonNull(state)) {
return SoftwareUpdateStatusType.of(state);
}
}
return null;
}

/**
* Depending on the returned value from getSoftwareUpdateStatus() this method returns a StringType of the status
* name, or 'UnDefType.NULL' if there is no such status.
*/
public State getSoftwareUpdateState() {
SoftwareUpdateStatusType softwareUpdateStatus = getSoftwareUpdateStatus();
return softwareUpdateStatus != null ? new StringType(softwareUpdateStatus.toString()) : UnDefType.NULL;
}

/**
* Set the speaker alarm sound.
*/
public Resource setAlarm(@Nullable Sound alarm) {
this.alarm = alarm;
return this;
}

/**
* Set the speaker alert sound. Note: this method sets the 'alert' JSON element. The 'alert' JSON element is
* used for both alert and alerts settings, so this method should only be used when setting an alert sound.
*/
public Resource setAlert(Sound alert) {
this.alert = GSON.toJsonTree(alert);
return this;
}

/**
* Set the speaker chime sound.
*/
public Resource setChime(@Nullable Sound chime) {
this.chime = chime;
return this;
}

/**
* Set the speaker mute state.
*/
public Resource setMute(@Nullable Mute mute) {
this.mute = mute;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2010-2025 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.hue.internal.api.dto.clip2;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.SoundType;

import com.google.gson.annotations.SerializedName;

/**
* DTO for a chime.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class Sound {
private @Nullable @SerializedName("sound_values") List<String> soundValues;
private @Nullable SoundStatus status;

public @Nullable SoundStatus getStatus() {
return this.status;
}

public List<SoundType> getSoundValues() {
List<String> soundValues = this.soundValues;
if (Objects.nonNull(soundValues)) {
return soundValues.stream().map(SoundType::of).collect(Collectors.toList());
}
return List.of();
}

public Sound setStatus(SoundStatus soundStatus) {
this.status = soundStatus;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2010-2025 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.hue.internal.api.dto.clip2;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.SoundType;

import com.google.gson.annotations.SerializedName;

/**
* DTO for 'sound status' of a chime.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class SoundStatus {
private @Nullable String sound;
private @Nullable @SerializedName("sound_values") List<String> soundValues;

public @Nullable SoundType getSound() {
String sound = this.sound;
return Objects.nonNull(sound) ? SoundType.of(sound) : null;
}

public List<SoundType> getSoundValues() {
List<String> soundValues = this.soundValues;
if (Objects.nonNull(soundValues)) {
return soundValues.stream().map(SoundType::of).collect(Collectors.toList());
}
return List.of();
}

public SoundStatus setSound(SoundType soundType) {
this.sound = soundType.name().toLowerCase();
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2010-2025 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.hue.internal.api.dto.clip2.enums;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
* Enum for sound mute state.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public enum MuteType {
MUTE,
UNMUTE;

public static MuteType of(@Nullable String value) {
if (value != null) {
try {
return valueOf(value.toUpperCase());
} catch (IllegalArgumentException e) {
// fall through
}
}
return UNMUTE;
}
}
Loading
Loading