[somneo] Add alarm support and other improvements (#14882)
* [somneo] Add alarm clock channels Signed-off-by: Michael Myrcik <michael.myrcik@web.de>pull/15109/head
parent
ff9254df75
commit
b505f7b12c
|
@ -13,47 +13,62 @@ This binding does only support one Thing:
|
|||
The Philips Somneo thing requires the `hostname` it can connect to.
|
||||
Its API only allows HTTPS access, but unfortunately the SSL certificate is not trusted and must be ignored by the parameter.
|
||||
|
||||
| Parameter | Values | Default |
|
||||
| --------------- | ------------------------------------ | ------- |
|
||||
| hostname | Hostname or IP address of the device | - |
|
||||
| port | Port number | 443 |
|
||||
| refreshInterval | Interval the device is polled in sec | 30 |
|
||||
| ignoreSSLErrors | Ignore SSL Errors | true |
|
||||
| Parameter | Values | Default |
|
||||
| ---------------------------- | ----------------------------------------------------------- | ------- |
|
||||
| hostname | Hostname or IP address of the device | - |
|
||||
| port | Port number | 443 |
|
||||
| refreshInterval | Interval the device is polled in sec | 30 |
|
||||
| refreshIntervalAlarmExtended | Interval the device is polled in sec (alarm clock settings) | 30 |
|
||||
| ignoreSSLErrors | Ignore SSL Errors | true |
|
||||
|
||||
## Channels
|
||||
|
||||
| Channel | Type | Read/Write | Description |
|
||||
| --------------------- | -------------------- | ---------- | ------------------------------------------------------ |
|
||||
| _Sensor_ | | | |
|
||||
| sensor#illuminance | Number:Illuminance | R | The current illuminance in lux |
|
||||
| sensor#temperature | Number:Temperature | R | The current temperature |
|
||||
| sensor#humidity | Number:Dimensionless | R | The current humidity in % |
|
||||
| sensor#noise | Number:Dimensionless | R | The current noise in dB |
|
||||
| _Light_ | | | |
|
||||
| light#main | Switch | RW | Turn the light on, off and set the brightness |
|
||||
| light#night | Switch | RW | Turn the night light on or off |
|
||||
| _Sunset_ | | | |
|
||||
| sunset#switch | Switch | RW | Turn the sunset program on or off |
|
||||
| sunset#remainingTime | Number:Time | R | Remaining time from an activated program |
|
||||
| sunset#lightIntensity | Dimmer | RW | Set the brightness during the sunset programme |
|
||||
| sunset#duration | Number:Time | RW | The duration of sunset program in minutes |
|
||||
| sunset#colorSchema | Number | RW | Choose a personal sunset |
|
||||
| sunset#ambientNoise | String | RW | Ambient noise played during the sunset |
|
||||
| sunset#volume | Dimmer | RW | Set the volume during the sunset programme |
|
||||
| _Relax_ | | | |
|
||||
| relax#switch | Switch | RW | Turn the relax breathe program on or off |
|
||||
| relax#remainingTime | Number:Time | R | Remaining time from an activated program |
|
||||
| relax#breathingRate | Number | RW | Breathing rate per minute during the relax program |
|
||||
| relax#duration | Number:Time | RW | The duration of breathe program in minutes |
|
||||
| relax#guidanceType | Number | RW | Select a breath guidance type during the relax program |
|
||||
| relax#lightIntensity | Dimmer | RW | Set the brightness during the breathe programme |
|
||||
| relax#volume | Dimmer | RW | Set the volume during the breathe programme |
|
||||
| _Audio_ | | | |
|
||||
| audio#radio | Player | RW | Controlling the radio and seeking for a frequency |
|
||||
| audio#aux | Switch | RW | Turn the AUX input on or off |
|
||||
| audio#volume | Dimmer | RW | Change the sound volume of the device |
|
||||
| audio#preset | String | RW | The Device has 5 presets to store radio frequencies |
|
||||
| audio#frequency | String | R | The currently selected radio frequency |
|
||||
| Channel | Type | Read/Write | Description |
|
||||
| ------------------------- | -------------------- | ---------- | ------------------------------------------------------- |
|
||||
| _Sensor_ | | | |
|
||||
| sensor#illuminance | Number:Illuminance | R | The current illuminance in lux |
|
||||
| sensor#temperature | Number:Temperature | R | The current temperature |
|
||||
| sensor#humidity | Number:Dimensionless | R | The current humidity in % |
|
||||
| sensor#noise | Number:Dimensionless | R | The current noise in dB |
|
||||
| _Light_ | | | |
|
||||
| light#main | Switch | RW | Turn the light on, off and set the brightness |
|
||||
| light#night | Switch | RW | Turn the night light on or off |
|
||||
| _Sunset_ | | | |
|
||||
| sunset#switch | Switch | RW | Turn the sunset program on or off |
|
||||
| sunset#remainingTime | Number:Time | R | Remaining time from an activated program |
|
||||
| sunset#lightIntensity | Dimmer | RW | Set the brightness during the sunset programme |
|
||||
| sunset#duration | Number:Time | RW | The duration of sunset program in minutes |
|
||||
| sunset#colorSchema | Number | RW | Choose a personal sunset |
|
||||
| sunset#ambientNoise | String | RW | Ambient noise played during the sunset |
|
||||
| sunset#volume | Dimmer | RW | Set the volume during the sunset programme |
|
||||
| _Relax_ | | | |
|
||||
| relax#switch | Switch | RW | Turn the relax breathe program on or off |
|
||||
| relax#remainingTime | Number:Time | R | Remaining time from an activated program |
|
||||
| relax#breathingRate | Number | RW | Breathing rate per minute during the relax program |
|
||||
| relax#duration | Number:Time | RW | The duration of breathe program in minutes |
|
||||
| relax#guidanceType | Number | RW | Select a breath guidance type during the relax program |
|
||||
| relax#lightIntensity | Dimmer | RW | Set the brightness during the breathe programme |
|
||||
| relax#volume | Dimmer | RW | Set the volume during the breathe programme |
|
||||
| _Audio_ | | | |
|
||||
| audio#radio | Player | RW | Controlling the radio and seeking for a frequency |
|
||||
| audio#aux | Switch | RW | Turn the AUX input on or off |
|
||||
| audio#volume | Dimmer | RW | Change the sound volume of the device |
|
||||
| audio#preset | String | RW | The Device has 5 presets to store radio frequencies |
|
||||
| audio#frequency | String | R | The currently selected radio frequency |
|
||||
| _Alarm_ | | | |
|
||||
| alarm#snooze | Number:Time | RW | The duration of the snooze function in minutes |
|
||||
| _Alarm[1...16]_ | | | |
|
||||
| alarm[]#configured | Switch | RW | The duration of the snooze function in minutes |
|
||||
| alarm[]#switch | Switch | RW | Turn the alarm clock on or off |
|
||||
| alarm[]#repeatDay | Number | RW | The days on which the alarm is repeated |
|
||||
| alarm[]#alarmTime | DateTime | RW | Alarm clock time |
|
||||
| alarm[]#powerWake | Switch | RW | Turn the power wake on or off |
|
||||
| alarm[]#powerWakeDelay | Number:Time | RW | How long after the normal alarm should Power Wake start |
|
||||
| alarm[]#sunriseDuration | Number:Time | RW | The duration of sunrise program in minutes |
|
||||
| alarm[]#sunriseBrightness | Dimmer | RW | The channel allows to set the sunrise light intensity |
|
||||
| alarm[]#sunriseSchema | Number | RW | Choose a personal sunrise |
|
||||
| alarm[]#sound | String | RW | The type of sound used for the alarm sound |
|
||||
| alarm[]#volume | Dimmer | RW | Change the sound volume of the alarm clock |
|
||||
|
||||
## Full Example
|
||||
|
||||
|
@ -96,6 +111,59 @@ Switch PhilipsSomneo_AudioAux "AUX-Input" ["Switch", "P
|
|||
Dimmer PhilipsSomneo_AudioVolume "Volume" <SoundVolume> ["Control", "SoundVolume"] { channel="somneo:hf367x:1:audio#volume" }
|
||||
String PhilipsSomneo_AudioPreset "FM Preset" ["Control"] { channel="somneo:hf367x:1:audio#preset" }
|
||||
String PhilipsSomneo_AudioFrequency "FM Frequency" ["Status"] { channel="somneo:hf367x:1:audio#frequency" }
|
||||
// Alarm
|
||||
Number:Time PhilipsSomneo_AlarmSnooze "Alarm Snooze" ["Control", "Duration"] { channel="somneo:hf367x:1:alarm#snooze" }
|
||||
|
||||
Switch PhilipsSomneo_Alarm1Switch "Alarm Clock" ["Switch", "Power"] { channel="somneo:hf367x:1:alarm1#switch" }
|
||||
DateTime PhilipsSomneo_Alarm1Time "Alarm Clock Time" <Time> ["Control"] { channel="somneo:hf367x:1:alarm1#alarmTime" }
|
||||
Number PhilipsSomneo_Alarm1RepeatDay "Repeat on [JS(somneorepeatday.js):%s]" <calendar> ["Control"] { channel="somneo:hf367x:1:alarm1#repeatDay" }
|
||||
Switch PhilipsSomneo_Alarm1PowerWake "Power Wake" ["Control"] { channel="somneo:hf367x:1:alarm1#powerWake" }
|
||||
Number:Time PhilipsSomneo_Alarm1PowerWakeDelay "Power Wake Delay" <Time> ["Control", "Duration"] { channel="somneo:hf367x:1:alarm1#powerWakeDelay" }
|
||||
Number:Time PhilipsSomneo_Alarm1SunriseDuration "Sunrise Duration" <Time> ["Control", "Duration"] { channel="somneo:hf367x:1:alarm1#sunriseDuration" }
|
||||
Dimmer PhilipsSomneo_Alarm1SunriseBrightness "Sunrise Brightness" <Light> ["Control", "Light"] { channel="somneo:hf367x:1:alarm1#sunriseBrightness" }
|
||||
Number PhilipsSomneo_Alarm1SunriseSchema "Sunrise Color" <sunrise> ["Control", "ColorTemperature"] { channel="somneo:hf367x:1:alarm1#sunriseSchema" }
|
||||
String PhilipsSomneo_Alarm1Sound "Sound" ["Control"] { channel="somneo:hf367x:1:alarm1#sound" }
|
||||
Dimmer PhilipsSomneo_Alarm1Volume "Volume" <SoundVolume> ["Control", "SoundVolume"] { channel="somneo:hf367x:1:alarm1#volume" }
|
||||
```
|
||||
|
||||
transform/somneorepeatday.js
|
||||
```javascript
|
||||
(function(i) {
|
||||
if (i == 254) {
|
||||
return "Daily";
|
||||
}
|
||||
if (i == 192) {
|
||||
return "Weekend";
|
||||
}
|
||||
if (i == 62) {
|
||||
return "Weekdays";
|
||||
}
|
||||
days = [];
|
||||
[
|
||||
["Sunday", 128],
|
||||
["Saturday", 64],
|
||||
["Friday", 32],
|
||||
["Thursday", 16],
|
||||
["Wednesday", 8],
|
||||
["Tuesday", 4],
|
||||
["Monday", 2]
|
||||
].forEach(function (x) {
|
||||
if (i >= x[1]) {
|
||||
days.push(x[0]);
|
||||
i = i % x[1];
|
||||
}
|
||||
});
|
||||
|
||||
if (days.length === 0) {
|
||||
return "Never";
|
||||
}
|
||||
if (days.length == 1) {
|
||||
return days[0];
|
||||
}
|
||||
return days.reverse().map(function(x) {
|
||||
return x.slice(0, 2);
|
||||
}).join(" ");
|
||||
})(input)
|
||||
```
|
||||
|
||||
somneo.sitemap:
|
||||
|
@ -140,6 +208,81 @@ sitemap somneo label="Philips Somneo" {
|
|||
Default item=PhilipsSomneo_AudioPreset visibility=[PhilipsSomneo_AudioRadio==PLAY]
|
||||
Default item=PhilipsSomneo_AudioFrequency visibility=[PhilipsSomneo_AudioRadio==PLAY]
|
||||
}
|
||||
Frame label="Alarm Common" {
|
||||
Setpoint item=PhilipsSomneo_AlarmSnooze minValue=1 maxValue=20
|
||||
Text label="Alarms" icon="settings" {
|
||||
Default item=PhilipsSomneo_Alarm3Configured
|
||||
Default item=PhilipsSomneo_Alarm4Configured
|
||||
Default item=PhilipsSomneo_Alarm5Configured
|
||||
Default item=PhilipsSomneo_Alarm6Configured
|
||||
Default item=PhilipsSomneo_Alarm7Configured
|
||||
Default item=PhilipsSomneo_Alarm8Configured
|
||||
Default item=PhilipsSomneo_Alarm9Configured
|
||||
Default item=PhilipsSomneo_Alarm10Configured
|
||||
Default item=PhilipsSomneo_Alarm11Configured
|
||||
Default item=PhilipsSomneo_Alarm12Configured
|
||||
Default item=PhilipsSomneo_Alarm13Configured
|
||||
Default item=PhilipsSomneo_Alarm14Configured
|
||||
Default item=PhilipsSomneo_Alarm15Configured
|
||||
Default item=PhilipsSomneo_Alarm16Configured
|
||||
}
|
||||
}
|
||||
Frame label="Alarm [1]" {
|
||||
Default item=PhilipsSomneo_Alarm1Switch
|
||||
Default item=PhilipsSomneo_Alarm1Time
|
||||
Default item=PhilipsSomneo_Alarm1PowerWake
|
||||
Slider item=PhilipsSomneo_Alarm1PowerWakeDelay minValue=0 maxValue=59
|
||||
Slider item=PhilipsSomneo_Alarm1RepeatDay minValue=0 maxValue=254 step=2
|
||||
Text label="Settings" icon="settings" {
|
||||
Default item=PhilipsSomneo_Alarm1SunriseDuration
|
||||
Slider item=PhilipsSomneo_Alarm1SunriseBrightness
|
||||
Selection item=PhilipsSomneo_Alarm1SunriseSchema
|
||||
Default item=PhilipsSomneo_Alarm1Sound
|
||||
Default item=PhilipsSomneo_Alarm1Volume
|
||||
}
|
||||
}
|
||||
Frame label="Alarm [2]"{
|
||||
Default item=PhilipsSomneo_Alarm2Switch
|
||||
Default item=PhilipsSomneo_Alarm2Time
|
||||
Default item=PhilipsSomneo_Alarm2PowerWake
|
||||
Slider item=PhilipsSomneo_Alarm2PowerWakeDelay minValue=0 maxValue=59
|
||||
Slider item=PhilipsSomneo_Alarm2RepeatDay minValue=0 maxValue=254 step=2
|
||||
Text label="Settings" icon="settings" {
|
||||
Default item=PhilipsSomneo_Alarm2SunriseDuration
|
||||
Slider item=PhilipsSomneo_Alarm2SunriseBrightness minValue=4 maxValue=100 step=4
|
||||
Selection item=PhilipsSomneo_Alarm2SunriseSchema
|
||||
Default item=PhilipsSomneo_Alarm2Sound
|
||||
Slider item=PhilipsSomneo_Alarm2Volume minValue=4 maxValue=100 step=4
|
||||
}
|
||||
}
|
||||
Frame label="Alarm [3]" visibility=[PhilipsSomneo_Alarm3Configured==ON] {
|
||||
Default item=PhilipsSomneo_Alarm3Switch
|
||||
Default item=PhilipsSomneo_Alarm3Time
|
||||
Default item=PhilipsSomneo_Alarm3PowerWake
|
||||
Slider item=PhilipsSomneo_Alarm3PowerWakeDelay minValue=0 maxValue=59
|
||||
Slider item=PhilipsSomneo_Alarm3RepeatDay minValue=0 maxValue=254 step=2
|
||||
Text label="Settings" icon="settings" {
|
||||
Default item=PhilipsSomneo_Alarm3SunriseDuration
|
||||
Slider item=PhilipsSomneo_Alarm3SunriseBrightness minValue=4 maxValue=100 step=4
|
||||
Selection item=PhilipsSomneo_Alarm3SunriseSchema
|
||||
Default item=PhilipsSomneo_Alarm3Sound
|
||||
Slider item=PhilipsSomneo_Alarm3Volume minValue=4 maxValue=100 step=4
|
||||
}
|
||||
}
|
||||
Frame label="Alarm [4]" visibility=[PhilipsSomneo_Alarm4Configured==ON] {
|
||||
Default item=PhilipsSomneo_Alarm4Switch
|
||||
Default item=PhilipsSomneo_Alarm4Time
|
||||
Default item=PhilipsSomneo_Alarm4PowerWake
|
||||
Slider item=PhilipsSomneo_Alarm4PowerWakeDelay minValue=0 maxValue=59
|
||||
Slider item=PhilipsSomneo_Alarm4RepeatDay minValue=0 maxValue=254 step=2
|
||||
Text label="Settings" icon="settings" {
|
||||
Default item=PhilipsSomneo_Alarm4SunriseDuration
|
||||
Slider item=PhilipsSomneo_Alarm4SunriseBrightness minValue=4 maxValue=100 step=4
|
||||
Selection item=PhilipsSomneo_Alarm4SunriseSchema
|
||||
Default item=PhilipsSomneo_Alarm4Sound
|
||||
Slider item=PhilipsSomneo_Alarm4Volume minValue=4 maxValue=100 step=4
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -58,6 +58,21 @@ public class SomneoBindingConstants {
|
|||
public static final String CHANNEL_SUNSET_REMAINING_TIME = "sunset#remainingTime";
|
||||
public static final String CHANNEL_SUNSET_SWITCH = "sunset#switch";
|
||||
public static final String CHANNEL_SUNSET_VOLUME = "sunset#volume";
|
||||
public static final String CHANNEL_ALARM_SNOOZE = "alarm#snooze";
|
||||
public static final String CHANNEL_ALARM_CONFIGURED = "alarm%d#configured";
|
||||
public static final String CHANNEL_ALARM_SWITCH = "alarm%d#switch";
|
||||
public static final String CHANNEL_ALARM_TIME = "alarm%d#alarmTime";
|
||||
public static final String CHANNEL_ALARM_REPEAT_DAY = "alarm%d#repeatDay";
|
||||
public static final String CHANNEL_ALARM_POWER_WAKE = "alarm%d#powerWake";
|
||||
public static final String CHANNEL_ALARM_POWER_WAKE_DELAY = "alarm%d#powerWakeDelay";
|
||||
public static final String CHANNEL_ALARM_SUNRISE_DURATION = "alarm%d#sunriseDuration";
|
||||
public static final String CHANNEL_ALARM_SUNRISE_BRIGHTNESS = "alarm%d#sunriseBrightness";
|
||||
public static final String CHANNEL_ALARM_SUNRISE_SCHEMA = "alarm%d#sunriseSchema";
|
||||
public static final String CHANNEL_ALARM_SOUND = "alarm%d#sound";
|
||||
public static final String CHANNEL_ALARM_VOLUME = "alarm%d#volume";
|
||||
|
||||
// Regex for alarm channels
|
||||
public static final String CHANNEL_ALARM_PREFIX_REGEX = "^alarm(\\d{1,2})#\\w+$";
|
||||
|
||||
// List of all Web Service Endpoints
|
||||
public static final String AUDIO_ENDPOINT = "/1/wuply";
|
||||
|
@ -71,4 +86,8 @@ public class SomneoBindingConstants {
|
|||
public static final String SENSORS_ENDPOINT = "/1/wusrd";
|
||||
public static final String SUNSET_ENDPOINT = "/1/wudsk";
|
||||
public static final String WIFI_ENDPOINT = "/0/wifi";
|
||||
public static final String ALARM_STATES_ENDPOINT = "/1/wualm/aenvs";
|
||||
public static final String ALARM_SCHEDULES_ENDPOINT = "/1/wualm/aalms";
|
||||
public static final String ALARM_SETTINGS_ENDPOINT = "/1/wualm";
|
||||
public static final String ALARM_EDIT_ENDPOINT = "/1/wualm/prfwu";
|
||||
}
|
||||
|
|
|
@ -25,5 +25,6 @@ public class SomneoConfiguration {
|
|||
public String hostname = "";
|
||||
public int port = 443;
|
||||
public int refreshInterval = 30;
|
||||
public int refreshIntervalAlarmExtended = 300;
|
||||
public boolean ignoreSSLErrors = false;
|
||||
}
|
||||
|
|
|
@ -16,14 +16,20 @@ import static org.openhab.binding.somneo.internal.SomneoBindingConstants.*;
|
|||
|
||||
import java.io.EOFException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.somneo.internal.model.AlarmSchedulesData;
|
||||
import org.openhab.binding.somneo.internal.model.AlarmSettingsData;
|
||||
import org.openhab.binding.somneo.internal.model.AlarmStateData;
|
||||
import org.openhab.binding.somneo.internal.model.AudioData;
|
||||
import org.openhab.binding.somneo.internal.model.DeviceData;
|
||||
import org.openhab.binding.somneo.internal.model.FirmwareData;
|
||||
|
@ -35,6 +41,7 @@ import org.openhab.binding.somneo.internal.model.SensorData;
|
|||
import org.openhab.binding.somneo.internal.model.SunsetData;
|
||||
import org.openhab.binding.somneo.internal.model.TimerData;
|
||||
import org.openhab.binding.somneo.internal.model.WifiData;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.NextPreviousType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
@ -52,6 +59,7 @@ import org.openhab.core.thing.binding.BaseThingHandler;
|
|||
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;
|
||||
|
||||
|
@ -70,10 +78,13 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
|
||||
private final SomneoPresetStateDescriptionProvider provider;
|
||||
|
||||
private final Pattern alarmPattern;
|
||||
|
||||
/**
|
||||
* Job to poll data from the device.
|
||||
*/
|
||||
private @Nullable ScheduledFuture<?> pollingJob;
|
||||
private @Nullable ScheduledFuture<?> pollingJobExtended;
|
||||
|
||||
/**
|
||||
* Job to count down the remaining program time.
|
||||
|
@ -97,6 +108,7 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
super(thing);
|
||||
this.httpClientProvider = httpClientProvider;
|
||||
this.provider = provider;
|
||||
this.alarmPattern = Objects.requireNonNull(Pattern.compile(CHANNEL_ALARM_PREFIX_REGEX));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -104,20 +116,51 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
String channelId = channelUID.getId();
|
||||
logger.debug("Handle command '{}' for channel {}", command, channelId);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
this.poll();
|
||||
return;
|
||||
}
|
||||
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Matcher matcher = alarmPattern.matcher(channelId);
|
||||
int alarmPosition = 0;
|
||||
if (matcher.matches()) {
|
||||
// Replace alarm channel index with string format placeholder to match
|
||||
// constants.
|
||||
alarmPosition = Integer.parseInt(matcher.group(1));
|
||||
channelId = channelId.replace(alarmPosition + "#", "%d#");
|
||||
}
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
if (channelId.equals(CHANNEL_ALARM_SNOOZE)) {
|
||||
final State snooze = connector.fetchSnoozeDuration();
|
||||
updateState(CHANNEL_ALARM_SNOOZE, snooze);
|
||||
} else if (channelId.startsWith("alarm")) {
|
||||
updateAlarmExtended(alarmPosition);
|
||||
} else if (channelId.startsWith("sensor")) {
|
||||
updateSensors();
|
||||
} else if (channelId.startsWith("light")) {
|
||||
updateLights();
|
||||
} else if (channelId.equals(CHANNEL_RELAX_REMAINING_TIME)
|
||||
|| channelId.equals(CHANNEL_SUNSET_REMAINING_TIME)) {
|
||||
updateRemainingTimer();
|
||||
} else if (channelId.equals(CHANNEL_AUDIO_FREQUENCY)) {
|
||||
updateFrequency();
|
||||
} else if (channelId.startsWith("audio")) {
|
||||
updateLights();
|
||||
} else if (channelId.startsWith("sunset")) {
|
||||
updateSunset();
|
||||
} else if (channelId.startsWith("relax")) {
|
||||
updateRelax();
|
||||
} else {
|
||||
this.poll();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelId) {
|
||||
case CHANNEL_AUDIO_AUX:
|
||||
if (command instanceof OnOffType) {
|
||||
if (command instanceof OnOffType onOff) {
|
||||
boolean isOn = OnOffType.ON.equals(command);
|
||||
connector.switchAux(isOn);
|
||||
|
||||
|
@ -141,7 +184,7 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
break;
|
||||
case CHANNEL_AUDIO_RADIO:
|
||||
if (command instanceof PlayPauseType) {
|
||||
if (command instanceof PlayPauseType playPause) {
|
||||
boolean isPlaying = PlayPauseType.PLAY.equals(command);
|
||||
connector.switchRadio(isPlaying);
|
||||
|
||||
|
@ -161,8 +204,8 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
break;
|
||||
case CHANNEL_AUDIO_VOLUME:
|
||||
if (command instanceof PercentType) {
|
||||
connector.setAudioVolume(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof PercentType percent) {
|
||||
connector.setAudioVolume(percent.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_LIGHT_MAIN:
|
||||
|
@ -177,8 +220,8 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
updateState(CHANNEL_SUNSET_SWITCH, OnOffType.OFF);
|
||||
}
|
||||
}
|
||||
if (command instanceof PercentType) {
|
||||
int level = Integer.parseInt(command.toFullString());
|
||||
if (command instanceof PercentType percent) {
|
||||
int level = percent.intValue();
|
||||
|
||||
if (level > 0) {
|
||||
connector.setMainLightDimmer(level);
|
||||
|
@ -205,23 +248,23 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
break;
|
||||
case CHANNEL_RELAX_BREATHING_RATE:
|
||||
if (command instanceof DecimalType) {
|
||||
connector.setRelaxBreathingRate(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof DecimalType decimal) {
|
||||
connector.setRelaxBreathingRate(decimal.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_RELAX_DURATION:
|
||||
if (command instanceof DecimalType) {
|
||||
connector.setRelaxDuration(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof QuantityType quantity) {
|
||||
connector.setRelaxDuration(quantity.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_RELAX_GUIDANCE_TYPE:
|
||||
if (command instanceof DecimalType) {
|
||||
connector.setRelaxGuidanceType(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof DecimalType decimal) {
|
||||
connector.setRelaxGuidanceType(decimal.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_RELAX_LIGHT_INTENSITY:
|
||||
if (command instanceof PercentType) {
|
||||
connector.setRelaxLightIntensity(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof PercentType percent) {
|
||||
connector.setRelaxLightIntensity(percent.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_RELAX_SWITCH:
|
||||
|
@ -241,8 +284,8 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
break;
|
||||
case CHANNEL_RELAX_VOLUME:
|
||||
if (command instanceof PercentType) {
|
||||
connector.setRelaxVolume(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof PercentType percent) {
|
||||
connector.setRelaxVolume(percent.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SUNSET_AMBIENT_NOISE:
|
||||
|
@ -251,18 +294,18 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
break;
|
||||
case CHANNEL_SUNSET_COLOR_SCHEMA:
|
||||
if (command instanceof DecimalType) {
|
||||
connector.setSunsetColorSchema(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof DecimalType decimal) {
|
||||
connector.setSunsetColorSchema(decimal.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SUNSET_DURATION:
|
||||
if (command instanceof DecimalType) {
|
||||
connector.setSunsetDuration(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof QuantityType quantity) {
|
||||
connector.setSunsetDuration(quantity.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SUNSET_LIGHT_INTENSITY:
|
||||
if (command instanceof PercentType) {
|
||||
connector.setSunsetLightIntensity(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof PercentType percent) {
|
||||
connector.setSunsetLightIntensity(percent.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SUNSET_SWITCH:
|
||||
|
@ -282,8 +325,84 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
break;
|
||||
case CHANNEL_SUNSET_VOLUME:
|
||||
if (command instanceof PercentType) {
|
||||
connector.setSunsetVolume(Integer.parseInt(command.toFullString()));
|
||||
if (command instanceof PercentType percent) {
|
||||
connector.setSunsetVolume(percent.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_SNOOZE:
|
||||
if (command instanceof QuantityType quantity) {
|
||||
connector.setAlarmSnooze(quantity.intValue());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_CONFIGURED:
|
||||
if (alarmPosition > 2) {
|
||||
if (command instanceof OnOffType onOff) {
|
||||
connector.toggleAlarmConfiguration(alarmPosition, onOff);
|
||||
|
||||
if (OnOffType.ON.equals(command)) {
|
||||
updateAlarmExtended(alarmPosition);
|
||||
} else {
|
||||
resetAlarm(alarmPosition);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.info("Alarm 1 and 2 can not be unset");
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_SWITCH:
|
||||
if (command instanceof OnOffType onOff) {
|
||||
connector.toggleAlarm(alarmPosition, onOff);
|
||||
updateAlarmExtended(alarmPosition);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_TIME:
|
||||
if (command instanceof DateTimeType decimal) {
|
||||
connector.setAlarmTime(alarmPosition, decimal);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_REPEAT_DAY:
|
||||
if (command instanceof DecimalType decimal) {
|
||||
connector.setAlarmRepeatDay(alarmPosition, decimal);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_POWER_WAKE:
|
||||
if (command instanceof OnOffType onOff) {
|
||||
connector.toggleAlarmPowerWake(alarmPosition, onOff);
|
||||
if (OnOffType.OFF.equals(command)) {
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE_DELAY, alarmPosition),
|
||||
QuantityType.valueOf(0, Units.MINUTE));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_POWER_WAKE_DELAY:
|
||||
if (command instanceof QuantityType quantity) {
|
||||
connector.setAlarmPowerWakeDelay(alarmPosition, quantity);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE, alarmPosition), OnOffType.ON);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_SUNRISE_DURATION:
|
||||
if (command instanceof QuantityType quantity) {
|
||||
connector.setAlarmSunriseDuration(alarmPosition, quantity);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_SUNRISE_BRIGHTNESS:
|
||||
if (command instanceof PercentType percent) {
|
||||
connector.setAlarmSunriseBrightness(alarmPosition, percent);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_SUNRISE_SCHEMA:
|
||||
if (command instanceof DecimalType decimal) {
|
||||
connector.setAlarmSunriseSchema(alarmPosition, decimal);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_SOUND:
|
||||
if (command instanceof StringType) {
|
||||
connector.setAlarmSound(alarmPosition, (StringType) command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALARM_VOLUME:
|
||||
if (command instanceof PercentType percent) {
|
||||
connector.setAlarmVolume(alarmPosition, percent);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -391,19 +510,30 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
int refreshInterval = getConfigAs(SomneoConfiguration.class).refreshInterval;
|
||||
logger.debug("Start polling job at interval {}s", refreshInterval);
|
||||
final SomneoConfiguration config = getConfigAs(SomneoConfiguration.class);
|
||||
final int refreshInterval = config.refreshInterval;
|
||||
logger.debug("Start default polling job at interval {}s", refreshInterval);
|
||||
this.pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, refreshInterval, TimeUnit.SECONDS);
|
||||
|
||||
final int refreshIntervalAlarmExtended = config.refreshIntervalAlarmExtended;
|
||||
logger.debug("Start extended alarm polling job at interval {}s", refreshIntervalAlarmExtended);
|
||||
this.pollingJobExtended = scheduler.scheduleWithFixedDelay(this::pollAlarmExtended, 0,
|
||||
refreshIntervalAlarmExtended, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void stopPolling() {
|
||||
final ScheduledFuture<?> pollingJob = this.pollingJob;
|
||||
if (pollingJob == null || pollingJob.isCancelled()) {
|
||||
return;
|
||||
if (pollingJob != null) {
|
||||
pollingJob.cancel(true);
|
||||
this.pollingJob = null;
|
||||
}
|
||||
|
||||
final ScheduledFuture<?> pollingJobExtended = this.pollingJobExtended;
|
||||
if (pollingJobExtended != null) {
|
||||
pollingJobExtended.cancel(true);
|
||||
this.pollingJobExtended = null;
|
||||
}
|
||||
|
||||
pollingJob.cancel(true);
|
||||
this.pollingJob = null;
|
||||
logger.debug("HTTP polling stopped.");
|
||||
}
|
||||
|
||||
|
@ -414,41 +544,20 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
|
||||
try {
|
||||
final SensorData sensorData = connector.fetchSensorData();
|
||||
updateState(CHANNEL_SENSOR_HUMIDITY, sensorData.getCurrentHumidity());
|
||||
updateState(CHANNEL_SENSOR_ILLUMINANCE, sensorData.getCurrentIlluminance());
|
||||
updateState(CHANNEL_SENSOR_NOISE, sensorData.getCurrentNoise());
|
||||
updateState(CHANNEL_SENSOR_TEMPERATURE, sensorData.getCurrentTemperature());
|
||||
updateSensors();
|
||||
|
||||
final LightData lightData = connector.fetchLightData();
|
||||
updateState(CHANNEL_LIGHT_MAIN, lightData.getMainLightState());
|
||||
updateState(CHANNEL_LIGHT_NIGHT, lightData.getNightLightState());
|
||||
lastLightBrightness = lightData.getMainLightLevel();
|
||||
updateLights();
|
||||
|
||||
final SunsetData sunsetData = connector.fetchSunsetData();
|
||||
updateState(CHANNEL_SUNSET_SWITCH, sunsetData.getSwitchState());
|
||||
updateState(CHANNEL_SUNSET_LIGHT_INTENSITY, sunsetData.getLightIntensity());
|
||||
updateState(CHANNEL_SUNSET_DURATION, sunsetData.getDurationInMin());
|
||||
updateState(CHANNEL_SUNSET_COLOR_SCHEMA, sunsetData.getColorSchema());
|
||||
updateState(CHANNEL_SUNSET_AMBIENT_NOISE, sunsetData.getAmbientNoise());
|
||||
updateState(CHANNEL_SUNSET_VOLUME, sunsetData.getSoundVolume());
|
||||
updateSunset();
|
||||
|
||||
final RelaxData relaxData = connector.fetchRelaxData();
|
||||
updateState(CHANNEL_RELAX_SWITCH, relaxData.getSwitchState());
|
||||
updateState(CHANNEL_RELAX_BREATHING_RATE, relaxData.getBreathingRate());
|
||||
updateState(CHANNEL_RELAX_DURATION, relaxData.getDurationInMin());
|
||||
updateState(CHANNEL_RELAX_GUIDANCE_TYPE, relaxData.getGuidanceType());
|
||||
updateState(CHANNEL_RELAX_LIGHT_INTENSITY, relaxData.getLightIntensity());
|
||||
updateState(CHANNEL_RELAX_VOLUME, relaxData.getSoundVolume());
|
||||
updateRelax();
|
||||
|
||||
final AudioData audioData = connector.fetchAudioData();
|
||||
updateState(CHANNEL_AUDIO_RADIO, audioData.getRadioState());
|
||||
updateState(CHANNEL_AUDIO_AUX, audioData.getAuxState());
|
||||
updateState(CHANNEL_AUDIO_VOLUME, audioData.getVolumeState());
|
||||
updateState(CHANNEL_AUDIO_PRESET, audioData.getPresetState());
|
||||
updateAudio();
|
||||
|
||||
updateFrequency();
|
||||
|
||||
updateAlarm();
|
||||
|
||||
updateRemainingTimer();
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
@ -465,6 +574,70 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateAudio() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
final AudioData audioData = connector.fetchAudioData();
|
||||
updateState(CHANNEL_AUDIO_RADIO, audioData.getRadioState());
|
||||
updateState(CHANNEL_AUDIO_AUX, audioData.getAuxState());
|
||||
updateState(CHANNEL_AUDIO_VOLUME, audioData.getVolumeState());
|
||||
updateState(CHANNEL_AUDIO_PRESET, audioData.getPresetState());
|
||||
}
|
||||
|
||||
private void updateRelax() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
final RelaxData relaxData = connector.fetchRelaxData();
|
||||
updateState(CHANNEL_RELAX_SWITCH, relaxData.getSwitchState());
|
||||
updateState(CHANNEL_RELAX_BREATHING_RATE, relaxData.getBreathingRate());
|
||||
updateState(CHANNEL_RELAX_DURATION, relaxData.getDurationInMin());
|
||||
updateState(CHANNEL_RELAX_GUIDANCE_TYPE, relaxData.getGuidanceType());
|
||||
updateState(CHANNEL_RELAX_LIGHT_INTENSITY, relaxData.getLightIntensity());
|
||||
updateState(CHANNEL_RELAX_VOLUME, relaxData.getSoundVolume());
|
||||
}
|
||||
|
||||
private void updateSunset() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
final SunsetData sunsetData = connector.fetchSunsetData();
|
||||
updateState(CHANNEL_SUNSET_SWITCH, sunsetData.getSwitchState());
|
||||
updateState(CHANNEL_SUNSET_LIGHT_INTENSITY, sunsetData.getLightIntensity());
|
||||
updateState(CHANNEL_SUNSET_DURATION, sunsetData.getDurationInMin());
|
||||
updateState(CHANNEL_SUNSET_COLOR_SCHEMA, sunsetData.getColorSchema());
|
||||
updateState(CHANNEL_SUNSET_AMBIENT_NOISE, sunsetData.getAmbientNoise());
|
||||
updateState(CHANNEL_SUNSET_VOLUME, sunsetData.getSoundVolume());
|
||||
}
|
||||
|
||||
private void updateLights() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
final LightData lightData = connector.fetchLightData();
|
||||
updateState(CHANNEL_LIGHT_MAIN, lightData.getMainLightState());
|
||||
updateState(CHANNEL_LIGHT_NIGHT, lightData.getNightLightState());
|
||||
lastLightBrightness = lightData.getMainLightLevel();
|
||||
}
|
||||
|
||||
private void updateSensors() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SensorData sensorData = connector.fetchSensorData();
|
||||
updateState(CHANNEL_SENSOR_HUMIDITY, sensorData.getCurrentHumidity());
|
||||
updateState(CHANNEL_SENSOR_ILLUMINANCE, sensorData.getCurrentIlluminance());
|
||||
updateState(CHANNEL_SENSOR_NOISE, sensorData.getCurrentNoise());
|
||||
updateState(CHANNEL_SENSOR_TEMPERATURE, sensorData.getCurrentTemperature());
|
||||
}
|
||||
|
||||
private void updateFrequency() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
|
@ -541,4 +714,117 @@ public class SomneoHandler extends BaseThingHandler {
|
|||
stopRemainingTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAlarm() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final State snooze = connector.fetchSnoozeDuration();
|
||||
updateState(CHANNEL_ALARM_SNOOZE, snooze);
|
||||
|
||||
final AlarmStateData alarmState = connector.fetchAlarmStateData();
|
||||
final AlarmSchedulesData alarmSchedulesData = connector.fetchAlarmScheduleData();
|
||||
|
||||
for (int i = 1; i <= alarmState.getAlarmCount(); i++) {
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_CONFIGURED, i), alarmState.getConfiguredState(i));
|
||||
|
||||
if (OnOffType.ON.equals(alarmState.getConfiguredState(i))) {
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SWITCH, i), alarmState.getEnabledState(i));
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_TIME, i),
|
||||
alarmSchedulesData.getAlarmTimeState(i));
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_REPEAT_DAY, i),
|
||||
alarmSchedulesData.getRepeatDayState(i));
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE, i), alarmState.getPowerWakeState(i));
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE_DELAY, i),
|
||||
alarmState.getPowerWakeDelayState(i, alarmSchedulesData.getAlarmTime(i)));
|
||||
} else {
|
||||
resetAlarm(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void pollAlarmExtended() {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final AlarmStateData alarmState = connector.fetchAlarmStateData();
|
||||
|
||||
for (int i = 1; i <= alarmState.getAlarmCount(); i++) {
|
||||
if (OnOffType.ON.equals(alarmState.getConfiguredState(i))) {
|
||||
updateAlarmExtended(i);
|
||||
} else {
|
||||
resetAlarm(i);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
logger.debug("Polling extended alarm data interrupted");
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (TimeoutException | ExecutionException e) {
|
||||
if (e.getCause() instanceof EOFException) {
|
||||
// Occurs on parallel mobile app access
|
||||
logger.debug("EOF: {}", e.getMessage());
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAlarmExtended(int position) throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final SomneoHttpConnector connector = this.connector;
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final AlarmSettingsData alarmSettings = connector.fetchAlarmSettingsData(position);
|
||||
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_CONFIGURED, position),
|
||||
alarmSettings.getConfiguredState());
|
||||
|
||||
if (OnOffType.ON.equals(alarmSettings.getConfiguredState())) {
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SWITCH, position), alarmSettings.getEnabledState());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE, position),
|
||||
alarmSettings.getPowerWakeState());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE_DELAY, position),
|
||||
alarmSettings.getPowerWakeDelayState());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_TIME, position), alarmSettings.getAlarmTimeState());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_REPEAT_DAY, position),
|
||||
alarmSettings.getRepeatDayState());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SUNRISE_DURATION, position),
|
||||
alarmSettings.getSunriseDurationInMin());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SUNRISE_BRIGHTNESS, position),
|
||||
alarmSettings.getSunriseBrightness());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SUNRISE_SCHEMA, position),
|
||||
alarmSettings.getSunriseSchema());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SOUND, position), alarmSettings.getSound());
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_VOLUME, position), alarmSettings.getSoundVolume());
|
||||
} else {
|
||||
resetAlarm(position);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetAlarm(int position) throws TimeoutException, InterruptedException, ExecutionException {
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SWITCH, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE_DELAY, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_TIME, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_REPEAT_DAY, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SUNRISE_DURATION, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SUNRISE_BRIGHTNESS, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SUNRISE_SCHEMA, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_SOUND, position), UnDefType.UNDEF);
|
||||
updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_VOLUME, position), UnDefType.UNDEF);
|
||||
}
|
||||
|
||||
private String formatAlarmChannelIdByIndex(String channelId, int index) {
|
||||
final String channelIdFormated = String.format(channelId, index);
|
||||
if (channelIdFormated == null) {
|
||||
return "";
|
||||
}
|
||||
return channelIdFormated;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,13 @@ import static org.openhab.binding.somneo.internal.SomneoBindingConstants.*;
|
|||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalTime;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.measure.quantity.Time;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
|
@ -28,6 +31,9 @@ import org.eclipse.jetty.client.api.Request;
|
|||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.somneo.internal.model.AlarmSchedulesData;
|
||||
import org.openhab.binding.somneo.internal.model.AlarmSettingsData;
|
||||
import org.openhab.binding.somneo.internal.model.AlarmStateData;
|
||||
import org.openhab.binding.somneo.internal.model.AudioData;
|
||||
import org.openhab.binding.somneo.internal.model.DeviceData;
|
||||
import org.openhab.binding.somneo.internal.model.FirmwareData;
|
||||
|
@ -40,10 +46,21 @@ import org.openhab.binding.somneo.internal.model.SunsetData;
|
|||
import org.openhab.binding.somneo.internal.model.TimerData;
|
||||
import org.openhab.binding.somneo.internal.model.WifiData;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
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.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* The {@link SomneoHttpConnector} is responsible for sending commands.
|
||||
|
@ -290,11 +307,163 @@ public class SomneoHttpConnector {
|
|||
return executeUrl("GET", PRESET_ENDPOINT, PresetData.class);
|
||||
}
|
||||
|
||||
public AlarmStateData fetchAlarmStateData() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
return executeUrl("GET", ALARM_STATES_ENDPOINT, AlarmStateData.class);
|
||||
}
|
||||
|
||||
public AlarmSchedulesData fetchAlarmScheduleData()
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
return executeUrl("GET", ALARM_SCHEDULES_ENDPOINT, AlarmSchedulesData.class);
|
||||
}
|
||||
|
||||
public AlarmSettingsData fetchAlarmSettingsData(final int position)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final String responseBody = executeUrl("PUT", ALARM_SETTINGS_ENDPOINT, "{\"prfnr\":" + (position) + "}");
|
||||
AlarmSettingsData data = (AlarmSettingsData) gson.fromJson(responseBody, AlarmSettingsData.class);
|
||||
if (data == null) {
|
||||
return new AlarmSettingsData();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public State fetchSnoozeDuration() throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final JsonObject response = executeUrl("GET", ALARM_SETTINGS_ENDPOINT, JsonObject.class);
|
||||
final JsonElement snooze = response.get("snztm");
|
||||
if (snooze == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new QuantityType<>(snooze.getAsInt(), Units.MINUTE);
|
||||
}
|
||||
|
||||
public void setAlarmSnooze(int snooze) throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final JsonObject data = new JsonObject();
|
||||
data.addProperty("snztm", snooze);
|
||||
executeUrl("PUT", ALARM_SETTINGS_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void toggleAlarmConfiguration(int position, OnOffType command)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = AlarmSettingsData.withDefaultValues(position);
|
||||
|
||||
if (OnOffType.ON.equals(command)) {
|
||||
final LocalTime now = LocalTime.now();
|
||||
if (now == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.setConfigured(true);
|
||||
data.setEnabled(true);
|
||||
data.setAlarmTime(now);
|
||||
data.setRepeatDay(0);
|
||||
} else {
|
||||
data.setConfigured(false);
|
||||
data.setEnabled(false);
|
||||
}
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void toggleAlarm(int position, OnOffType enabled)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.setPosition(position);
|
||||
data.setEnabledState(enabled);
|
||||
if (OnOffType.ON.equals(enabled)) {
|
||||
data.setConfigured(true);
|
||||
}
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmTime(int position, DateTimeType time)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = fetchAlarmSettingsData(position);
|
||||
data.setConfigured(true);
|
||||
data.setAlarmTime(time);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmRepeatDay(int position, DecimalType days)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.setPosition(position);
|
||||
data.setConfigured(true);
|
||||
data.setRepeatDayState(days);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void toggleAlarmPowerWake(int position, OnOffType state)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = fetchAlarmSettingsData(position);
|
||||
data.setPosition(position);
|
||||
data.setPowerWakeState(state);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmPowerWakeDelay(int position, QuantityType<Time> time)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = fetchAlarmSettingsData(position);
|
||||
data.setConfigured(true);
|
||||
data.setPowerWakeDelayState(time);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmSunriseDuration(int position, QuantityType<Time> duration)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.setPosition(position);
|
||||
data.setConfigured(true);
|
||||
data.setSunriseDurationState(duration);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmSunriseBrightness(int position, PercentType percent)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.setPosition(position);
|
||||
data.setConfigured(true);
|
||||
data.setSunriseBrightnessState(percent);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmSunriseSchema(int position, DecimalType schema)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.setPosition(position);
|
||||
data.setConfigured(true);
|
||||
data.setSunriseSchemaState(schema);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmSound(int position, StringType sound)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.setPosition(position);
|
||||
data.setConfigured(true);
|
||||
data.setAlarmSoundState(sound);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
public void setAlarmVolume(int position, PercentType volume)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.setPosition(position);
|
||||
data.setConfigured(true);
|
||||
data.setAlarmVolumeState(volume);
|
||||
|
||||
executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
|
||||
}
|
||||
|
||||
private <T> T executeUrl(String httpMethod, String endpoint, Class<T> classOfT)
|
||||
throws TimeoutException, InterruptedException, ExecutionException {
|
||||
final String responseBody = executeUrl("GET", endpoint, (String) null);
|
||||
final T data = gson.fromJson(responseBody, classOfT);
|
||||
return data;
|
||||
final String responseBody = executeUrl(httpMethod, endpoint, (String) null);
|
||||
return gson.fromJson(responseBody, classOfT);
|
||||
}
|
||||
|
||||
private void executeUrl(String httpMethod, String endpoint, Object data)
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2023 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.somneo.internal.model;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* This class represents the audio state from the API.
|
||||
*
|
||||
* @author Michael Myrcik - Initial contribution
|
||||
*/
|
||||
public class AlarmSchedulesData {
|
||||
|
||||
/**
|
||||
* None = 0,
|
||||
* Monday = 2,
|
||||
* Tuesday = 4,
|
||||
* Wednesday = 8,
|
||||
* Thursday = 16,
|
||||
* Friday = 32,
|
||||
* Saturday = 64,
|
||||
* Sunday = 128
|
||||
*/
|
||||
@SerializedName("daynm")
|
||||
private List<Integer> repeatDays;
|
||||
|
||||
@SerializedName("almhr")
|
||||
private List<Integer> hours;
|
||||
|
||||
@SerializedName("almmn")
|
||||
private List<Integer> minutes;
|
||||
|
||||
public @NonNull State getRepeatDayState(int position) {
|
||||
final List<Integer> repeatDays = this.repeatDays;
|
||||
if (repeatDays == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
final Integer repeatDay = repeatDays.get(position - 1);
|
||||
if (repeatDay == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new DecimalType(repeatDay);
|
||||
}
|
||||
|
||||
public LocalTime getAlarmTime(int position) {
|
||||
final List<Integer> hours = this.hours;
|
||||
if (hours == null) {
|
||||
return null;
|
||||
}
|
||||
final List<Integer> minutes = this.minutes;
|
||||
if (minutes == null) {
|
||||
return null;
|
||||
}
|
||||
final Integer hour = hours.get(position - 1);
|
||||
final Integer minute = minutes.get(position - 1);
|
||||
return LocalTime.of(hour, minute);
|
||||
}
|
||||
|
||||
public @NonNull State getAlarmTimeState(int position) {
|
||||
final LocalTime time = getAlarmTime(position);
|
||||
if (time == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
final String alarmTimeString = String.format("%02d:%02d:00", time.getHour(), time.getMinute());
|
||||
if (alarmTimeString == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return DateTimeType.valueOf(alarmTimeString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,352 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2023 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.somneo.internal.model;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import javax.measure.quantity.Time;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
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.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* This class represents the audio state from the API.
|
||||
*
|
||||
* @author Michael Myrcik - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AlarmSettingsData {
|
||||
|
||||
private static final int POWER_WAKE_ENABLED = 255;
|
||||
private static final int POWER_WAKE_DISABLED = 0;
|
||||
|
||||
@SerializedName("prfnr")
|
||||
private @Nullable Integer position;
|
||||
|
||||
@SerializedName("prfvs")
|
||||
private @Nullable Boolean configured;
|
||||
|
||||
@SerializedName("prfen")
|
||||
private @Nullable Boolean enabled;
|
||||
|
||||
/**
|
||||
* None = 0,
|
||||
* Monday = 2,
|
||||
* Tuesday = 4,
|
||||
* Wednesday = 8,
|
||||
* Thursday = 16,
|
||||
* Friday = 32,
|
||||
* Saturday = 64,
|
||||
* Sunday = 128
|
||||
*/
|
||||
@SerializedName("daynm")
|
||||
private @Nullable Integer repeatDay;
|
||||
|
||||
@SerializedName("almhr")
|
||||
private @Nullable Integer hour;
|
||||
|
||||
@SerializedName("almmn")
|
||||
private @Nullable Integer minute;
|
||||
|
||||
/**
|
||||
* Brightness range from 0 to 25.
|
||||
*/
|
||||
@SerializedName("curve")
|
||||
private @Nullable Integer sunriseBrightness;
|
||||
|
||||
@SerializedName("durat")
|
||||
private @Nullable Integer sunriseDurationInMin;
|
||||
|
||||
@SerializedName("ctype")
|
||||
private @Nullable Integer sunriseSchema;
|
||||
|
||||
@SerializedName("snddv")
|
||||
private @Nullable String soundSource;
|
||||
|
||||
@SerializedName("sndch")
|
||||
private @Nullable String soundChannel;
|
||||
|
||||
@SerializedName("sndlv")
|
||||
private @Nullable Integer soundVolume;
|
||||
|
||||
@SerializedName("pwrsz")
|
||||
private @Nullable Integer powerWake;
|
||||
|
||||
@SerializedName("pszhr")
|
||||
private @Nullable Integer powerWakeHour;
|
||||
|
||||
@SerializedName("pszmn")
|
||||
private @Nullable Integer powerWakeMinute;
|
||||
|
||||
public void setPosition(Integer position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public State getConfiguredState() {
|
||||
final Boolean configured = this.configured;
|
||||
if (configured == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return OnOffType.from(configured);
|
||||
}
|
||||
|
||||
public void setConfigured(Boolean configured) {
|
||||
this.configured = configured;
|
||||
}
|
||||
|
||||
public State getEnabledState() {
|
||||
final Boolean enabled = this.enabled;
|
||||
if (enabled == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return OnOffType.from(enabled);
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public void setEnabledState(OnOffType enabled) {
|
||||
setEnabled(OnOffType.ON.equals(enabled));
|
||||
}
|
||||
|
||||
public void setAlarmTime(LocalTime time) {
|
||||
Integer powerWakeDelay = getPowerWakeDelay();
|
||||
if (powerWakeDelay == null) {
|
||||
powerWakeDelay = 0;
|
||||
}
|
||||
this.hour = time.getHour();
|
||||
this.minute = time.getMinute();
|
||||
|
||||
final Integer powerWake = this.powerWake;
|
||||
if (powerWake != null && powerWake.intValue() == POWER_WAKE_ENABLED) {
|
||||
LocalTime powerWakeTime = time.plusMinutes(powerWakeDelay);
|
||||
this.powerWakeHour = powerWakeTime.getHour();
|
||||
this.powerWakeMinute = powerWakeTime.getMinute();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAlarmTime(DateTimeType timeState) {
|
||||
final ZonedDateTime zonedTime = timeState.getZonedDateTime();
|
||||
final LocalTime time = LocalTime.of(zonedTime.getHour(), zonedTime.getMinute());
|
||||
if (time == null) {
|
||||
return;
|
||||
}
|
||||
setAlarmTime(time);
|
||||
}
|
||||
|
||||
public State getRepeatDayState() {
|
||||
final Integer repeatDay = this.repeatDay;
|
||||
if (repeatDay == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new DecimalType(repeatDay);
|
||||
}
|
||||
|
||||
public void setRepeatDay(int days) {
|
||||
this.repeatDay = days;
|
||||
}
|
||||
|
||||
public void setRepeatDayState(DecimalType days) {
|
||||
setRepeatDay(days.intValue());
|
||||
}
|
||||
|
||||
public State getAlarmTimeState() {
|
||||
final Integer hour = this.hour;
|
||||
if (hour == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
final Integer minute = this.minute;
|
||||
if (minute == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
final String alarmTimeString = String.format("%02d:%02d:00", hour, minute);
|
||||
if (alarmTimeString == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return DateTimeType.valueOf(alarmTimeString);
|
||||
}
|
||||
|
||||
public State getPowerWakeState() {
|
||||
final Integer powerWake = this.powerWake;
|
||||
if (powerWake == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return OnOffType.from((int) powerWake == POWER_WAKE_ENABLED);
|
||||
}
|
||||
|
||||
public void setPowerWakeState(OnOffType state) {
|
||||
if (OnOffType.ON.equals(state)) {
|
||||
powerWake = POWER_WAKE_ENABLED;
|
||||
powerWakeHour = hour;
|
||||
powerWakeMinute = minute;
|
||||
} else {
|
||||
powerWake = POWER_WAKE_DISABLED;
|
||||
powerWakeHour = 0;
|
||||
powerWakeMinute = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable Integer getPowerWakeDelay() {
|
||||
if (OnOffType.OFF.equals(getPowerWakeState())) {
|
||||
return Integer.valueOf(0);
|
||||
}
|
||||
final Integer hour = this.hour;
|
||||
if (hour == null) {
|
||||
return null;
|
||||
}
|
||||
final Integer minute = this.minute;
|
||||
if (minute == null) {
|
||||
return null;
|
||||
}
|
||||
final Integer powerWakeHour = this.powerWakeHour;
|
||||
if (powerWakeHour == null) {
|
||||
return null;
|
||||
}
|
||||
final Integer powerWakeMinute = this.powerWakeMinute;
|
||||
if (powerWakeMinute == null) {
|
||||
return null;
|
||||
}
|
||||
int delay = powerWakeMinute - minute;
|
||||
if (!powerWakeHour.equals(hour)) {
|
||||
// Simplify the algorithm, as the delta cannot be greater than 59 minutes.
|
||||
delay += 60;
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
public void setPowerWakeDelay(int minutes) {
|
||||
final Integer hour = this.hour;
|
||||
if (hour == null) {
|
||||
return;
|
||||
}
|
||||
final Integer minute = this.minute;
|
||||
if (minute == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
LocalTime localTime = LocalTime.of(hour, minute);
|
||||
localTime = localTime.plusMinutes(minutes);
|
||||
|
||||
this.powerWake = POWER_WAKE_ENABLED;
|
||||
this.powerWakeHour = localTime.getHour();
|
||||
this.powerWakeMinute = localTime.getMinute();
|
||||
}
|
||||
|
||||
public void setPowerWakeDelayState(QuantityType<Time> time) {
|
||||
setPowerWakeDelay(time.intValue());
|
||||
}
|
||||
|
||||
public State getPowerWakeDelayState() {
|
||||
final Integer delay = getPowerWakeDelay();
|
||||
if (delay == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new QuantityType<>(delay, Units.MINUTE);
|
||||
}
|
||||
|
||||
public State getSunriseBrightness() {
|
||||
final Integer sunriseBrightness = this.sunriseBrightness;
|
||||
if (sunriseBrightness == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new PercentType(sunriseBrightness * 4);
|
||||
}
|
||||
|
||||
public void setSunriseBrightnessState(PercentType percent) {
|
||||
sunriseBrightness = percent.intValue() / 4;
|
||||
}
|
||||
|
||||
public State getSunriseDurationInMin() {
|
||||
final Integer sunriseDurationInMin = this.sunriseDurationInMin;
|
||||
if (sunriseDurationInMin == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new QuantityType<>(sunriseDurationInMin, Units.MINUTE);
|
||||
}
|
||||
|
||||
public void setSunriseDurationState(QuantityType<Time> duration) {
|
||||
sunriseDurationInMin = duration.intValue();
|
||||
}
|
||||
|
||||
public State getSunriseSchema() {
|
||||
final Integer sunriseSchema = this.sunriseSchema;
|
||||
if (sunriseSchema == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new DecimalType(sunriseSchema);
|
||||
}
|
||||
|
||||
public void setSunriseSchemaState(DecimalType schema) {
|
||||
this.sunriseSchema = schema.intValue();
|
||||
}
|
||||
|
||||
public State getSound() {
|
||||
final String soundSource = this.soundSource;
|
||||
if (soundSource == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
final String suffix = "off".equals(soundSource) ? "" : "-" + soundChannel;
|
||||
return new StringType(soundSource + suffix);
|
||||
}
|
||||
|
||||
public void setAlarmSoundState(StringType sound) {
|
||||
final String[] values = sound.toFullString().split("-");
|
||||
soundSource = values[0];
|
||||
soundChannel = values.length == 1 ? "" : values[1];
|
||||
}
|
||||
|
||||
public State getSoundVolume() {
|
||||
final Integer soundVolume = this.soundVolume;
|
||||
if (soundVolume == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new PercentType(soundVolume * 4);
|
||||
}
|
||||
|
||||
public void setAlarmVolumeState(PercentType volume) {
|
||||
soundVolume = volume.intValue() / 4;
|
||||
}
|
||||
|
||||
public static AlarmSettingsData withDefaultValues(int position) {
|
||||
final AlarmSettingsData data = new AlarmSettingsData();
|
||||
data.position = position;
|
||||
data.configured = false;
|
||||
data.enabled = false;
|
||||
data.hour = 7;
|
||||
data.minute = 30;
|
||||
data.powerWake = POWER_WAKE_DISABLED;
|
||||
data.powerWakeHour = 0;
|
||||
data.powerWakeMinute = 0;
|
||||
data.sunriseSchema = 0;
|
||||
data.sunriseBrightness = 20;
|
||||
data.sunriseDurationInMin = 30;
|
||||
data.repeatDay = 254;
|
||||
data.soundSource = "wus";
|
||||
data.soundChannel = "1";
|
||||
data.soundVolume = 12;
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2023 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.somneo.internal.model;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* This class represents the alarm state from the API.
|
||||
*
|
||||
* @author Michael Myrcik - Initial contribution
|
||||
*/
|
||||
public class AlarmStateData {
|
||||
|
||||
private static final int POWER_WAKE_ENABLED = 255;
|
||||
|
||||
@SerializedName("prfen")
|
||||
private List<Boolean> enabled;
|
||||
|
||||
@SerializedName("prfvs")
|
||||
private List<Boolean> configured;
|
||||
|
||||
@SerializedName("pwrsv")
|
||||
private List<Integer> powerWake;
|
||||
|
||||
public @NonNull State getEnabledState(int position) {
|
||||
final List<Boolean> enabled = this.enabled;
|
||||
if (enabled == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return OnOffType.from(enabled.get(position - 1));
|
||||
}
|
||||
|
||||
public @NonNull State getConfiguredState(int position) {
|
||||
final List<Boolean> configured = this.configured;
|
||||
if (configured == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return OnOffType.from(configured.get(position - 1));
|
||||
}
|
||||
|
||||
public @NonNull State getPowerWakeState(int position) {
|
||||
final List<Integer> powerWake = this.powerWake;
|
||||
if (powerWake == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
position -= 1;
|
||||
position *= 3;
|
||||
return OnOffType.from((int) powerWake.get(position) == POWER_WAKE_ENABLED);
|
||||
}
|
||||
|
||||
public @NonNull State getPowerWakeDelayState(int position, LocalTime alarmTime) {
|
||||
final State powerWakeState = getPowerWakeState(position);
|
||||
if (UnDefType.NULL.equals(powerWakeState)) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
if (OnOffType.OFF.equals(powerWakeState)) {
|
||||
return QuantityType.valueOf(0, Units.MINUTE);
|
||||
}
|
||||
if (alarmTime == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
|
||||
final LocalTime powerWakeTime = getPowerWakeTime(position);
|
||||
if (powerWakeTime == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
|
||||
Duration delay = Duration.between(alarmTime, powerWakeTime);
|
||||
if (delay == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
|
||||
return QuantityType.valueOf(delay.toMinutes(), Units.MINUTE);
|
||||
}
|
||||
|
||||
private LocalTime getPowerWakeTime(int position) {
|
||||
final List<Integer> powerWake = this.powerWake;
|
||||
if (powerWake == null) {
|
||||
return null;
|
||||
}
|
||||
position--;
|
||||
position *= 3;
|
||||
final Integer hour = powerWake.get(position + 1);
|
||||
final Integer minute = powerWake.get(position + 2);
|
||||
return LocalTime.of(hour, minute);
|
||||
}
|
||||
|
||||
public int getAlarmCount() {
|
||||
final List<Boolean> configured = this.configured;
|
||||
if (configured == null) {
|
||||
return 0;
|
||||
}
|
||||
return configured.size();
|
||||
}
|
||||
}
|
|
@ -17,6 +17,8 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
|
@ -83,7 +85,7 @@ public class RelaxData {
|
|||
if (durationInMin == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new DecimalType(durationInMin);
|
||||
return new QuantityType<>(durationInMin, Units.MINUTE);
|
||||
}
|
||||
|
||||
public void setDurationInMin(int durationInMin) {
|
||||
|
|
|
@ -17,7 +17,9 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
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.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
|
||||
|
@ -87,7 +89,7 @@ public class SunsetData {
|
|||
if (durationInMin == null) {
|
||||
return UnDefType.NULL;
|
||||
}
|
||||
return new DecimalType(durationInMin);
|
||||
return new QuantityType<>(durationInMin, Units.MINUTE);
|
||||
}
|
||||
|
||||
public void setDurationInMin(int durationInMin) {
|
||||
|
|
|
@ -1,12 +1,31 @@
|
|||
# add-on
|
||||
|
||||
addon.somneo.name = Somneo Binding
|
||||
addon.somneo.description = This is the binding for Philips Somneo devices.
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.somneo.hf367x.label = Philips Somneo Light
|
||||
thing-type.somneo.hf367x.description = A smart sleep and wake-up light with sensors.
|
||||
thing-type.somneo.hf367x.group.alarm1.label = Alarm 1
|
||||
thing-type.somneo.hf367x.group.alarm10.label = Alarm 10
|
||||
thing-type.somneo.hf367x.group.alarm11.label = Alarm 11
|
||||
thing-type.somneo.hf367x.group.alarm12.label = Alarm 12
|
||||
thing-type.somneo.hf367x.group.alarm13.label = Alarm 13
|
||||
thing-type.somneo.hf367x.group.alarm14.label = Alarm 14
|
||||
thing-type.somneo.hf367x.group.alarm15.label = Alarm 15
|
||||
thing-type.somneo.hf367x.group.alarm16.label = Alarm 16
|
||||
thing-type.somneo.hf367x.group.alarm2.label = Alarm 2
|
||||
thing-type.somneo.hf367x.group.alarm3.label = Alarm 3
|
||||
thing-type.somneo.hf367x.group.alarm4.label = Alarm 4
|
||||
thing-type.somneo.hf367x.group.alarm5.label = Alarm 5
|
||||
thing-type.somneo.hf367x.group.alarm6.label = Alarm 6
|
||||
thing-type.somneo.hf367x.group.alarm7.label = Alarm 7
|
||||
thing-type.somneo.hf367x.group.alarm8.label = Alarm 8
|
||||
thing-type.somneo.hf367x.group.alarm9.label = Alarm 9
|
||||
|
||||
# thing types config
|
||||
|
||||
# thing type config description
|
||||
thing-type.config.somneo.hf367x.hostname.label = Hostname
|
||||
thing-type.config.somneo.hf367x.hostname.description = Hostname or IP address of the device.
|
||||
thing-type.config.somneo.hf367x.ignoreSSLErrors.label = Ignore SSL Errors
|
||||
|
@ -15,8 +34,17 @@ thing-type.config.somneo.hf367x.port.label = HTTP Port
|
|||
thing-type.config.somneo.hf367x.port.description = HTTP Port used for communication. Normally shouldn't be changed.
|
||||
thing-type.config.somneo.hf367x.refreshInterval.label = Refresh Interval
|
||||
thing-type.config.somneo.hf367x.refreshInterval.description = Interval the device is polled in sec.
|
||||
thing-type.config.somneo.hf367x.refreshIntervalAlarmExtended.label = Refresh Interval for extended alarm clock settings
|
||||
thing-type.config.somneo.hf367x.refreshIntervalAlarmExtended.description = Interval the device is polled in seconds. This polling triggers a sync icon on the device.
|
||||
|
||||
# channel group types
|
||||
|
||||
channel-group-type.somneo.alarm.label = Alarm Clock
|
||||
channel-group-type.somneo.alarm.description = Channels to control alarm clock.
|
||||
channel-group-type.somneo.alarmCommon.label = Common Alarm Clock Settings
|
||||
channel-group-type.somneo.alarmCommon.description = Channels to control alarm clock settings that affect all alarm clocks.
|
||||
channel-group-type.somneo.alarmErasable.label = Alarm Clock
|
||||
channel-group-type.somneo.alarmErasable.description = Channels to control alarm clock.
|
||||
channel-group-type.somneo.audio.label = Audio Player
|
||||
channel-group-type.somneo.audio.description = Channels to control the audio player.
|
||||
channel-group-type.somneo.audio.channel.aux.label = AUX Input
|
||||
|
@ -25,26 +53,46 @@ channel-group-type.somneo.audio.channel.radio.label = Radio Remote Control
|
|||
channel-group-type.somneo.audio.channel.radio.description = Remote control for controlling the radio and seeking for a frequency.
|
||||
channel-group-type.somneo.light.label = Light
|
||||
channel-group-type.somneo.light.description = Different light channels.
|
||||
channel-group-type.somneo.sensor.label = Sensor Data
|
||||
channel-group-type.somneo.sensor.description = Data from the various sensors.
|
||||
channel-group-type.somneo.relax.label = Relax Breathe
|
||||
channel-group-type.somneo.relax.description = Light-guided breathing helps you relax for sleep.
|
||||
channel-group-type.somneo.relax.channel.lightIntensity.label = Light Intensity
|
||||
channel-group-type.somneo.relax.channel.lightIntensity.description = The channel allows to set the light intensity.
|
||||
channel-group-type.somneo.relax.channel.switch.label = Relax Breathe Program
|
||||
channel-group-type.somneo.relax.channel.switch.description = The switch channel allows to turn the relax breathe program on or off.
|
||||
channel-group-type.somneo.relax.channel.volume.label = Volume
|
||||
channel-group-type.somneo.relax.channel.volume.description = Set the volume of the relax breath program.
|
||||
channel-group-type.somneo.sensor.label = Sensor Data
|
||||
channel-group-type.somneo.sensor.description = Data from the various sensors.
|
||||
channel-group-type.somneo.sunset.label = Sunset
|
||||
channel-group-type.somneo.sunset.description = Simulate a sunset with selectable lights and sounds.
|
||||
channel-group-type.somneo.sunset.channel.lightIntensity.label = Light Intensity
|
||||
channel-group-type.somneo.sunset.channel.lightIntensity.description = The channel allows to set the light intensity.
|
||||
channel-group-type.somneo.sunset.channel.lightIntensity.label = Sunset Brightness
|
||||
channel-group-type.somneo.sunset.channel.lightIntensity.description = The channel allows to set the sunset light intensity.
|
||||
channel-group-type.somneo.sunset.channel.switch.label = Sunset Program
|
||||
channel-group-type.somneo.sunset.channel.switch.description = The switch channel allows to turn the sunset program on or off.
|
||||
channel-group-type.somneo.sunset.channel.volume.label = Volume
|
||||
channel-group-type.somneo.sunset.channel.volume.description = Set the volume of the sunset program.
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.somneo.alarmConfigured.label = Configured
|
||||
channel-type.somneo.alarmConfigured.description = Indicates if this alarm is configured. Deactivating this switch clears the alarm.
|
||||
channel-type.somneo.alarmSnooze.label = Alarm Snooze
|
||||
channel-type.somneo.alarmSnooze.description = The duration of the snooze function in minutes.
|
||||
channel-type.somneo.alarmSound.label = Alarm Clock Sound
|
||||
channel-type.somneo.alarmSound.description = The type of sound used for the alarm clock sound.
|
||||
channel-type.somneo.alarmSound.state.option.off = No sound
|
||||
channel-type.somneo.alarmSound.state.option.wus-1 = Forest Birds
|
||||
channel-type.somneo.alarmSound.state.option.wus-2 = Summer Birds
|
||||
channel-type.somneo.alarmSound.state.option.wus-3 = Buddha Wakeup
|
||||
channel-type.somneo.alarmSound.state.option.wus-4 = Morning Alps
|
||||
channel-type.somneo.alarmSound.state.option.wus-5 = Yoga Harmony
|
||||
channel-type.somneo.alarmSound.state.option.wus-6 = Nepal Bowls
|
||||
channel-type.somneo.alarmSound.state.option.wus-7 = Summer Lake
|
||||
channel-type.somneo.alarmSound.state.option.wus-8 = Ocean Waves
|
||||
channel-type.somneo.alarmSound.state.option.fmr-1 = FM 1
|
||||
channel-type.somneo.alarmSound.state.option.fmr-2 = FM 2
|
||||
channel-type.somneo.alarmSound.state.option.fmr-3 = FM 3
|
||||
channel-type.somneo.alarmSound.state.option.fmr-4 = FM 4
|
||||
channel-type.somneo.alarmSound.state.option.fmr-5 = FM 5
|
||||
channel-type.somneo.alarmSwitch.label = Alarm Clock
|
||||
channel-type.somneo.alarmSwitch.description = Turn the alarm clock on or off.
|
||||
channel-type.somneo.alarmTime.label = Time
|
||||
channel-type.somneo.alarmTime.description = Alarm clock time.
|
||||
channel-type.somneo.alarmTime.state.pattern = %1$tH:%1$tM
|
||||
channel-type.somneo.ambientNoise.label = Ambient Noise
|
||||
channel-type.somneo.ambientNoise.description = Ambient noise played during the sunset.
|
||||
channel-type.somneo.ambientNoise.state.option.off = No sound
|
||||
|
@ -66,8 +114,10 @@ channel-type.somneo.breathingRate.state.option.4 = 7 BR/min
|
|||
channel-type.somneo.breathingRate.state.option.5 = 8 BR/min
|
||||
channel-type.somneo.breathingRate.state.option.6 = 9 BR/min
|
||||
channel-type.somneo.breathingRate.state.option.7 = 10 BR/min
|
||||
channel-type.somneo.brightness.label = Light Brightness
|
||||
channel-type.somneo.brightness.description = The channel allows to set the light intensity.
|
||||
channel-type.somneo.colorSchema.label = Color Schema
|
||||
channel-type.somneo.colorSchema.description = Choose a personal sunset.
|
||||
channel-type.somneo.colorSchema.description = Choose a personal sunrise or sunset.
|
||||
channel-type.somneo.colorSchema.state.option.0 = Sunny day
|
||||
channel-type.somneo.colorSchema.state.option.1 = Island red
|
||||
channel-type.somneo.colorSchema.state.option.2 = Nordic white
|
||||
|
@ -86,23 +136,49 @@ channel-type.somneo.light.label = Night Light
|
|||
channel-type.somneo.light.description = The light switch channel allows to turn the night light on or off.
|
||||
channel-type.somneo.noise.label = Noise
|
||||
channel-type.somneo.noise.description = The current noise in dB.
|
||||
channel-type.somneo.powerWakeDelay.label = Power Wake Delay
|
||||
channel-type.somneo.powerWakeDelay.description = How long after the normal alarm should Power Wake start.
|
||||
channel-type.somneo.powerWakeSwitch.label = Power Wake
|
||||
channel-type.somneo.powerWakeSwitch.description = Turn the power wake on or off.
|
||||
channel-type.somneo.preset.label = FM Preset
|
||||
channel-type.somneo.preset.description = The Device has 5 presets to store radio frequencies.
|
||||
channel-type.somneo.relaxDuration.label = Duration
|
||||
channel-type.somneo.relaxDuration.description = The duration of relax breathe program in minutes.
|
||||
channel-type.somneo.relaxDuration.state.option.5 = 5 Minutes
|
||||
channel-type.somneo.relaxDuration.state.option.10 = 10 Minutes
|
||||
channel-type.somneo.relaxDuration.state.option.15 = 15 Minutes
|
||||
channel-type.somneo.relaxDuration.state.option.5\ min = 5 Minutes
|
||||
channel-type.somneo.relaxDuration.state.option.10\ min = 10 Minutes
|
||||
channel-type.somneo.relaxDuration.state.option.15\ min = 15 Minutes
|
||||
channel-type.somneo.remainingTime.label = Remaining Time
|
||||
channel-type.somneo.remainingTime.description = Remaining time from an activated program.
|
||||
channel-type.somneo.remainingTime.state.pattern = %1$tM:%1$tS min
|
||||
channel-type.somneo.repeatDay.label = Days
|
||||
channel-type.somneo.repeatDay.description = The days on which the alarm is repeated.
|
||||
channel-type.somneo.sunriseBrightness.label = Sunrise Brightness
|
||||
channel-type.somneo.sunriseBrightness.description = The channel allows to set the sunrise light intensity.
|
||||
channel-type.somneo.sunriseDuration.label = Sunrise Duration
|
||||
channel-type.somneo.sunriseDuration.description = The duration of sunrise program in minutes.
|
||||
channel-type.somneo.sunriseDuration.state.option.5\ min = 5 Minutes
|
||||
channel-type.somneo.sunriseDuration.state.option.10\ min = 10 Minutes
|
||||
channel-type.somneo.sunriseDuration.state.option.15\ min = 15 Minutes
|
||||
channel-type.somneo.sunriseDuration.state.option.20\ min = 20 Minutes
|
||||
channel-type.somneo.sunriseDuration.state.option.25\ min = 25 Minutes
|
||||
channel-type.somneo.sunriseDuration.state.option.30\ min = 30 Minutes
|
||||
channel-type.somneo.sunriseDuration.state.option.35\ min = 35 Minutes
|
||||
channel-type.somneo.sunriseDuration.state.option.40\ min = 40 Minutes
|
||||
channel-type.somneo.sunsetDuration.label = Duration
|
||||
channel-type.somneo.sunsetDuration.description = The duration of sunset program in minutes.
|
||||
channel-type.somneo.sunsetDuration.state.option.5 = 5 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.10 = 10 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.15 = 15 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.20 = 20 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.30 = 30 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.45 = 45 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.60 = 60 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.5\ min = 5 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.10\ min = 10 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.15\ min = 15 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.20\ min = 20 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.30\ min = 30 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.45\ min = 45 Minutes
|
||||
channel-type.somneo.sunsetDuration.state.option.60\ min = 60 Minutes
|
||||
channel-type.somneo.temperature.label = Temperature
|
||||
channel-type.somneo.temperature.description = The current temperature in °C.
|
||||
|
||||
# channel group types
|
||||
|
||||
channel-group-type.somneo.relax.channel.volume.label = Volume
|
||||
channel-group-type.somneo.relax.channel.volume.description = Set the volume of the relax breath program.
|
||||
channel-group-type.somneo.sunset.channel.volume.label = Volume
|
||||
channel-group-type.somneo.sunset.channel.volume.description = Set the volume of the sunset program.
|
||||
|
|
|
@ -14,8 +14,62 @@
|
|||
<channel-group id="sunset" typeId="sunset"/>
|
||||
<channel-group id="relax" typeId="relax"/>
|
||||
<channel-group id="audio" typeId="audio"/>
|
||||
<channel-group id="alarm" typeId="alarmCommon"/>
|
||||
<channel-group id="alarm1" typeId="alarm">
|
||||
<label>Alarm 1</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm2" typeId="alarm">
|
||||
<label>Alarm 2</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm3" typeId="alarmErasable">
|
||||
<label>Alarm 3</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm4" typeId="alarmErasable">
|
||||
<label>Alarm 4</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm5" typeId="alarmErasable">
|
||||
<label>Alarm 5</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm6" typeId="alarmErasable">
|
||||
<label>Alarm 6</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm7" typeId="alarmErasable">
|
||||
<label>Alarm 7</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm8" typeId="alarmErasable">
|
||||
<label>Alarm 8</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm9" typeId="alarmErasable">
|
||||
<label>Alarm 9</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm10" typeId="alarmErasable">
|
||||
<label>Alarm 10</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm11" typeId="alarmErasable">
|
||||
<label>Alarm 11</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm12" typeId="alarmErasable">
|
||||
<label>Alarm 12</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm13" typeId="alarmErasable">
|
||||
<label>Alarm 13</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm14" typeId="alarmErasable">
|
||||
<label>Alarm 14</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm15" typeId="alarmErasable">
|
||||
<label>Alarm 15</label>
|
||||
</channel-group>
|
||||
<channel-group id="alarm16" typeId="alarmErasable">
|
||||
<label>Alarm 16</label>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<properties>
|
||||
<property name="thingTypeVersion">1</property>
|
||||
<property name="vendor">Philips</property>
|
||||
</properties>
|
||||
|
||||
<config-description>
|
||||
<parameter name="hostname" type="text" required="true">
|
||||
<context>network-address</context>
|
||||
|
@ -34,6 +88,12 @@
|
|||
<default>30</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="refreshIntervalAlarmExtended" type="integer" unit="s" min="1">
|
||||
<label>Refresh Interval for extended alarm clock settings</label>
|
||||
<description>Interval the device is polled in seconds. This polling triggers a sync icon on the device.</description>
|
||||
<default>300</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="ignoreSSLErrors" type="boolean">
|
||||
<label>Ignore SSL Errors</label>
|
||||
<description>If set to true ignores invalid SSL certificate errors. This is potentially dangerous.</description>
|
||||
|
@ -43,6 +103,52 @@
|
|||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-group-type id="alarm">
|
||||
<label>Alarm Clock</label>
|
||||
<description>Channels to control alarm clock.</description>
|
||||
<category>Alarm</category>
|
||||
<channels>
|
||||
<channel id="switch" typeId="alarmSwitch"/>
|
||||
<channel id="repeatDay" typeId="repeatDay"/>
|
||||
<channel id="alarmTime" typeId="alarmTime"/>
|
||||
<channel id="powerWake" typeId="powerWakeSwitch"/>
|
||||
<channel id="powerWakeDelay" typeId="powerWakeDelay"/>
|
||||
<channel id="sunriseDuration" typeId="sunriseDuration"/>
|
||||
<channel id="sunriseBrightness" typeId="sunriseBrightness"/>
|
||||
<channel id="sunriseSchema" typeId="colorSchema"/>
|
||||
<channel id="sound" typeId="alarmSound"/>
|
||||
<channel id="volume" typeId="system.volume"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="alarmCommon">
|
||||
<label>Common Alarm Clock Settings</label>
|
||||
<description>Channels to control alarm clock settings that affect all alarm clocks.</description>
|
||||
<category>Alarm</category>
|
||||
<channels>
|
||||
<channel id="snooze" typeId="alarmSnooze"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="alarmErasable">
|
||||
<label>Alarm Clock</label>
|
||||
<description>Channels to control alarm clock.</description>
|
||||
<category>Alarm</category>
|
||||
<channels>
|
||||
<channel id="configured" typeId="alarmConfigured"/>
|
||||
<channel id="switch" typeId="alarmSwitch"/>
|
||||
<channel id="repeatDay" typeId="repeatDay"/>
|
||||
<channel id="alarmTime" typeId="alarmTime"/>
|
||||
<channel id="powerWake" typeId="powerWakeSwitch"/>
|
||||
<channel id="powerWakeDelay" typeId="powerWakeDelay"/>
|
||||
<channel id="sunriseDuration" typeId="sunriseDuration"/>
|
||||
<channel id="sunriseBrightness" typeId="sunriseBrightness"/>
|
||||
<channel id="sunriseSchema" typeId="colorSchema"/>
|
||||
<channel id="sound" typeId="alarmSound"/>
|
||||
<channel id="volume" typeId="system.volume"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="audio">
|
||||
<label>Audio Player</label>
|
||||
<description>Channels to control the audio player.</description>
|
||||
|
@ -67,7 +173,7 @@
|
|||
<description>Different light channels.</description>
|
||||
<category>Light</category>
|
||||
<channels>
|
||||
<channel id="main" typeId="system.brightness"/>
|
||||
<channel id="main" typeId="brightness"/>
|
||||
<channel id="night" typeId="light"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
@ -96,10 +202,7 @@
|
|||
<channel id="breathingRate" typeId="breathingRate"/>
|
||||
<channel id="duration" typeId="relaxDuration"/>
|
||||
<channel id="guidanceType" typeId="guidanceType"/>
|
||||
<channel id="lightIntensity" typeId="system.brightness">
|
||||
<label>Light Intensity</label>
|
||||
<description>The channel allows to set the light intensity.</description>
|
||||
</channel>
|
||||
<channel id="lightIntensity" typeId="sunriseBrightness"/>
|
||||
<channel id="volume" typeId="system.volume"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
@ -114,9 +217,9 @@
|
|||
<description>The switch channel allows to turn the sunset program on or off.</description>
|
||||
</channel>
|
||||
<channel id="remainingTime" typeId="remainingTime"/>
|
||||
<channel id="lightIntensity" typeId="system.brightness">
|
||||
<label>Light Intensity</label>
|
||||
<description>The channel allows to set the light intensity.</description>
|
||||
<channel id="lightIntensity" typeId="brightness">
|
||||
<label>Sunset Brightness</label>
|
||||
<description>The channel allows to set the sunset light intensity.</description>
|
||||
</channel>
|
||||
<channel id="duration" typeId="sunsetDuration"/>
|
||||
<channel id="colorSchema" typeId="colorSchema"/>
|
||||
|
@ -125,6 +228,80 @@
|
|||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-type id="alarmConfigured">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Configured</label>
|
||||
<description>Indicates if this alarm is configured. Deactivating this switch clears the alarm.</description>
|
||||
<category>Switch</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarmSnooze">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Alarm Snooze</label>
|
||||
<description>The duration of the snooze function in minutes.</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Duration</tag>
|
||||
</tags>
|
||||
<state pattern="%d min" min="1" max="20" step="1"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarmSound">
|
||||
<item-type>String</item-type>
|
||||
<label>Alarm Clock Sound</label>
|
||||
<description>The type of sound used for the alarm clock sound.</description>
|
||||
<category>Noise</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Noise</tag>
|
||||
</tags>
|
||||
<state>
|
||||
<options>
|
||||
<option value="off">No sound</option>
|
||||
<option value="wus-1">Forest Birds</option>
|
||||
<option value="wus-2">Summer Birds</option>
|
||||
<option value="wus-3">Buddha Wakeup</option>
|
||||
<option value="wus-4">Morning Alps</option>
|
||||
<option value="wus-5">Yoga Harmony</option>
|
||||
<option value="wus-6">Nepal Bowls</option>
|
||||
<option value="wus-7">Summer Lake</option>
|
||||
<option value="wus-8">Ocean Waves</option>
|
||||
<option value="fmr-1">FM 1</option>
|
||||
<option value="fmr-2">FM 2</option>
|
||||
<option value="fmr-3">FM 3</option>
|
||||
<option value="fmr-4">FM 4</option>
|
||||
<option value="fmr-5">FM 5</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarmSwitch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Alarm Clock</label>
|
||||
<description>Turn the alarm clock on or off.</description>
|
||||
<category>Switch</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Power</tag>
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="alarmTime">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Time</label>
|
||||
<description>Alarm clock time.</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Timestamp</tag>
|
||||
</tags>
|
||||
<state pattern="%1$tH:%1$tM"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambientNoise">
|
||||
<item-type>String</item-type>
|
||||
<label>Ambient Noise</label>
|
||||
|
@ -170,10 +347,22 @@
|
|||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="brightness">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Light Brightness</label>
|
||||
<description>The channel allows to set the light intensity.</description>
|
||||
<category>Light</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Light</tag>
|
||||
</tags>
|
||||
<state pattern="%d %%" min="0" max="100" step="4"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="colorSchema">
|
||||
<item-type>Number</item-type>
|
||||
<label>Color Schema</label>
|
||||
<description>Choose a personal sunset.</description>
|
||||
<description>Choose a personal sunrise or sunset.</description>
|
||||
<category>Sunset</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
|
@ -261,6 +450,29 @@
|
|||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="powerWakeDelay">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Power Wake Delay</label>
|
||||
<description>How long after the normal alarm should Power Wake start.</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Duration</tag>
|
||||
</tags>
|
||||
<state pattern="%d min" min="0" max="59" step="1"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="powerWakeSwitch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Power Wake</label>
|
||||
<description>Turn the power wake on or off.</description>
|
||||
<category>Switch</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Power</tag>
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="preset">
|
||||
<item-type>String</item-type>
|
||||
<label>FM Preset</label>
|
||||
|
@ -282,9 +494,9 @@
|
|||
</tags>
|
||||
<state>
|
||||
<options>
|
||||
<option value="5">5 Minutes</option>
|
||||
<option value="10">10 Minutes</option>
|
||||
<option value="15">15 Minutes</option>
|
||||
<option value="5 min">5 Minutes</option>
|
||||
<option value="10 min">10 Minutes</option>
|
||||
<option value="15 min">15 Minutes</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
@ -301,6 +513,52 @@
|
|||
<state pattern="%1$tM:%1$tS min" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="repeatDay">
|
||||
<item-type>Number</item-type>
|
||||
<label>Days</label>
|
||||
<description>The days on which the alarm is repeated.</description>
|
||||
<category>Calendar</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Timestamp</tag>
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sunriseBrightness">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Sunrise Brightness</label>
|
||||
<description>The channel allows to set the sunrise light intensity.</description>
|
||||
<category>Light</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Light</tag>
|
||||
</tags>
|
||||
<state pattern="%d %%" min="4" max="100" step="4"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sunriseDuration">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Sunrise Duration</label>
|
||||
<description>The duration of sunrise program in minutes.</description>
|
||||
<category>Time</category>
|
||||
<tags>
|
||||
<tag>Control</tag>
|
||||
<tag>Duration</tag>
|
||||
</tags>
|
||||
<state>
|
||||
<options>
|
||||
<option value="5 min">5 Minutes</option>
|
||||
<option value="10 min">10 Minutes</option>
|
||||
<option value="15 min">15 Minutes</option>
|
||||
<option value="20 min">20 Minutes</option>
|
||||
<option value="25 min">25 Minutes</option>
|
||||
<option value="30 min">30 Minutes</option>
|
||||
<option value="35 min">35 Minutes</option>
|
||||
<option value="40 min">40 Minutes</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sunsetDuration">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Duration</label>
|
||||
|
@ -312,13 +570,13 @@
|
|||
</tags>
|
||||
<state>
|
||||
<options>
|
||||
<option value="5">5 Minutes</option>
|
||||
<option value="10">10 Minutes</option>
|
||||
<option value="15">15 Minutes</option>
|
||||
<option value="20">20 Minutes</option>
|
||||
<option value="30">30 Minutes</option>
|
||||
<option value="45">45 Minutes</option>
|
||||
<option value="60">60 Minutes</option>
|
||||
<option value="5 min">5 Minutes</option>
|
||||
<option value="10 min">10 Minutes</option>
|
||||
<option value="15 min">15 Minutes</option>
|
||||
<option value="20 min">20 Minutes</option>
|
||||
<option value="30 min">30 Minutes</option>
|
||||
<option value="45 min">45 Minutes</option>
|
||||
<option value="60 min">60 Minutes</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
|
||||
|
||||
<thing-type uid="somneo:hf367x">
|
||||
<instruction-set targetVersion="1">
|
||||
<update-channel id="main" groupIds="light">
|
||||
<type>somneo:brightness</type>
|
||||
</update-channel>
|
||||
<update-channel id="lightIntensity" groupIds="sunset">
|
||||
<type>somneo:brightness</type>
|
||||
</update-channel>
|
||||
<update-channel id="lightIntensity" groupIds="relax">
|
||||
<type>somneo:sunriseBrightness</type>
|
||||
</update-channel>
|
||||
|
||||
<add-channel id="snooze" groupIds="alarm">
|
||||
<type>somneo:alarmSnooze</type>
|
||||
</add-channel>
|
||||
<add-channel id="configured"
|
||||
groupIds="alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:alarmConfigured</type>
|
||||
</add-channel>
|
||||
<add-channel id="switch"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:alarmSwitch</type>
|
||||
</add-channel>
|
||||
<add-channel id="repeatDay"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:repeatDay</type>
|
||||
</add-channel>
|
||||
<add-channel id="alarmTime"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:alarmTime</type>
|
||||
</add-channel>
|
||||
<add-channel id="powerWake"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:powerWakeSwitch</type>
|
||||
</add-channel>
|
||||
<add-channel id="powerWakeDelay"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:powerWakeDelay</type>
|
||||
</add-channel>
|
||||
<add-channel id="sunriseDuration"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:sunriseDuration</type>
|
||||
</add-channel>
|
||||
<add-channel id="sunriseBrightness"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:sunriseBrightness</type>
|
||||
</add-channel>
|
||||
<add-channel id="sunriseSchema"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:colorSchema</type>
|
||||
</add-channel>
|
||||
<add-channel id="sound"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>somneo:alarmSound</type>
|
||||
</add-channel>
|
||||
<add-channel id="volume"
|
||||
groupIds="alarm1,alarm2,alarm3,alarm4,alarm5,alarm6,alarm7,alarm8,alarm9,alarm10,alarm11,alarm12,alarm13,alarm14,alarm15,alarm16">
|
||||
<type>system:volume</type>
|
||||
</add-channel>
|
||||
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
</update:update-descriptions>
|
Loading…
Reference in New Issue