[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
0x4d4d 2023-06-17 12:55:27 +02:00 committed by GitHub
parent ff9254df75
commit b505f7b12c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1734 additions and 152 deletions

View File

@ -13,47 +13,62 @@ This binding does only support one Thing:
The Philips Somneo thing requires the `hostname` it can connect to. 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. Its API only allows HTTPS access, but unfortunately the SSL certificate is not trusted and must be ignored by the parameter.
| Parameter | Values | Default | | Parameter | Values | Default |
| --------------- | ------------------------------------ | ------- | | ---------------------------- | ----------------------------------------------------------- | ------- |
| hostname | Hostname or IP address of the device | - | | hostname | Hostname or IP address of the device | - |
| port | Port number | 443 | | port | Port number | 443 |
| refreshInterval | Interval the device is polled in sec | 30 | | refreshInterval | Interval the device is polled in sec | 30 |
| ignoreSSLErrors | Ignore SSL Errors | true | | refreshIntervalAlarmExtended | Interval the device is polled in sec (alarm clock settings) | 30 |
| ignoreSSLErrors | Ignore SSL Errors | true |
## Channels ## Channels
| Channel | Type | Read/Write | Description | | Channel | Type | Read/Write | Description |
| --------------------- | -------------------- | ---------- | ------------------------------------------------------ | | ------------------------- | -------------------- | ---------- | ------------------------------------------------------- |
| _Sensor_ | | | | | _Sensor_ | | | |
| sensor#illuminance | Number:Illuminance | R | The current illuminance in lux | | sensor#illuminance | Number:Illuminance | R | The current illuminance in lux |
| sensor#temperature | Number:Temperature | R | The current temperature | | sensor#temperature | Number:Temperature | R | The current temperature |
| sensor#humidity | Number:Dimensionless | R | The current humidity in % | | sensor#humidity | Number:Dimensionless | R | The current humidity in % |
| sensor#noise | Number:Dimensionless | R | The current noise in dB | | sensor#noise | Number:Dimensionless | R | The current noise in dB |
| _Light_ | | | | | _Light_ | | | |
| light#main | Switch | RW | Turn the light on, off and set the brightness | | light#main | Switch | RW | Turn the light on, off and set the brightness |
| light#night | Switch | RW | Turn the night light on or off | | light#night | Switch | RW | Turn the night light on or off |
| _Sunset_ | | | | | _Sunset_ | | | |
| sunset#switch | Switch | RW | Turn the sunset program on or off | | sunset#switch | Switch | RW | Turn the sunset program on or off |
| sunset#remainingTime | Number:Time | R | Remaining time from an activated program | | sunset#remainingTime | Number:Time | R | Remaining time from an activated program |
| sunset#lightIntensity | Dimmer | RW | Set the brightness during the sunset programme | | sunset#lightIntensity | Dimmer | RW | Set the brightness during the sunset programme |
| sunset#duration | Number:Time | RW | The duration of sunset program in minutes | | sunset#duration | Number:Time | RW | The duration of sunset program in minutes |
| sunset#colorSchema | Number | RW | Choose a personal sunset | | sunset#colorSchema | Number | RW | Choose a personal sunset |
| sunset#ambientNoise | String | RW | Ambient noise played during the sunset | | sunset#ambientNoise | String | RW | Ambient noise played during the sunset |
| sunset#volume | Dimmer | RW | Set the volume during the sunset programme | | sunset#volume | Dimmer | RW | Set the volume during the sunset programme |
| _Relax_ | | | | | _Relax_ | | | |
| relax#switch | Switch | RW | Turn the relax breathe program on or off | | relax#switch | Switch | RW | Turn the relax breathe program on or off |
| relax#remainingTime | Number:Time | R | Remaining time from an activated program | | relax#remainingTime | Number:Time | R | Remaining time from an activated program |
| relax#breathingRate | Number | RW | Breathing rate per minute during the relax 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#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#guidanceType | Number | RW | Select a breath guidance type during the relax program |
| relax#lightIntensity | Dimmer | RW | Set the brightness during the breathe programme | | relax#lightIntensity | Dimmer | RW | Set the brightness during the breathe programme |
| relax#volume | Dimmer | RW | Set the volume during the breathe programme | | relax#volume | Dimmer | RW | Set the volume during the breathe programme |
| _Audio_ | | | | | _Audio_ | | | |
| audio#radio | Player | RW | Controlling the radio and seeking for a frequency | | audio#radio | Player | RW | Controlling the radio and seeking for a frequency |
| audio#aux | Switch | RW | Turn the AUX input on or off | | audio#aux | Switch | RW | Turn the AUX input on or off |
| audio#volume | Dimmer | RW | Change the sound volume of the device | | 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#preset | String | RW | The Device has 5 presets to store radio frequencies |
| audio#frequency | String | R | The currently selected radio frequency | | 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 ## 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" } 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_AudioPreset "FM Preset" ["Control"] { channel="somneo:hf367x:1:audio#preset" }
String PhilipsSomneo_AudioFrequency "FM Frequency" ["Status"] { channel="somneo:hf367x:1:audio#frequency" } 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: somneo.sitemap:
@ -140,6 +208,81 @@ sitemap somneo label="Philips Somneo" {
Default item=PhilipsSomneo_AudioPreset visibility=[PhilipsSomneo_AudioRadio==PLAY] Default item=PhilipsSomneo_AudioPreset visibility=[PhilipsSomneo_AudioRadio==PLAY]
Default item=PhilipsSomneo_AudioFrequency 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
}
}
} }
``` ```

View File

@ -58,6 +58,21 @@ public class SomneoBindingConstants {
public static final String CHANNEL_SUNSET_REMAINING_TIME = "sunset#remainingTime"; 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_SWITCH = "sunset#switch";
public static final String CHANNEL_SUNSET_VOLUME = "sunset#volume"; 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 // List of all Web Service Endpoints
public static final String AUDIO_ENDPOINT = "/1/wuply"; 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 SENSORS_ENDPOINT = "/1/wusrd";
public static final String SUNSET_ENDPOINT = "/1/wudsk"; public static final String SUNSET_ENDPOINT = "/1/wudsk";
public static final String WIFI_ENDPOINT = "/0/wifi"; 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";
} }

View File

@ -25,5 +25,6 @@ public class SomneoConfiguration {
public String hostname = ""; public String hostname = "";
public int port = 443; public int port = 443;
public int refreshInterval = 30; public int refreshInterval = 30;
public int refreshIntervalAlarmExtended = 300;
public boolean ignoreSSLErrors = false; public boolean ignoreSSLErrors = false;
} }

View File

@ -16,14 +16,20 @@ import static org.openhab.binding.somneo.internal.SomneoBindingConstants.*;
import java.io.EOFException; import java.io.EOFException;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; 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.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient; 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.AudioData;
import org.openhab.binding.somneo.internal.model.DeviceData; import org.openhab.binding.somneo.internal.model.DeviceData;
import org.openhab.binding.somneo.internal.model.FirmwareData; 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.SunsetData;
import org.openhab.binding.somneo.internal.model.TimerData; import org.openhab.binding.somneo.internal.model.TimerData;
import org.openhab.binding.somneo.internal.model.WifiData; 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.DecimalType;
import org.openhab.core.library.types.NextPreviousType; import org.openhab.core.library.types.NextPreviousType;
import org.openhab.core.library.types.OnOffType; 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.Command;
import org.openhab.core.types.RefreshType; import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State; import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -70,10 +78,13 @@ public class SomneoHandler extends BaseThingHandler {
private final SomneoPresetStateDescriptionProvider provider; private final SomneoPresetStateDescriptionProvider provider;
private final Pattern alarmPattern;
/** /**
* Job to poll data from the device. * Job to poll data from the device.
*/ */
private @Nullable ScheduledFuture<?> pollingJob; private @Nullable ScheduledFuture<?> pollingJob;
private @Nullable ScheduledFuture<?> pollingJobExtended;
/** /**
* Job to count down the remaining program time. * Job to count down the remaining program time.
@ -97,6 +108,7 @@ public class SomneoHandler extends BaseThingHandler {
super(thing); super(thing);
this.httpClientProvider = httpClientProvider; this.httpClientProvider = httpClientProvider;
this.provider = provider; this.provider = provider;
this.alarmPattern = Objects.requireNonNull(Pattern.compile(CHANNEL_ALARM_PREFIX_REGEX));
} }
@Override @Override
@ -104,20 +116,51 @@ public class SomneoHandler extends BaseThingHandler {
String channelId = channelUID.getId(); String channelId = channelUID.getId();
logger.debug("Handle command '{}' for channel {}", command, channelId); 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 { 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) { switch (channelId) {
case CHANNEL_AUDIO_AUX: case CHANNEL_AUDIO_AUX:
if (command instanceof OnOffType) { if (command instanceof OnOffType onOff) {
boolean isOn = OnOffType.ON.equals(command); boolean isOn = OnOffType.ON.equals(command);
connector.switchAux(isOn); connector.switchAux(isOn);
@ -141,7 +184,7 @@ public class SomneoHandler extends BaseThingHandler {
} }
break; break;
case CHANNEL_AUDIO_RADIO: case CHANNEL_AUDIO_RADIO:
if (command instanceof PlayPauseType) { if (command instanceof PlayPauseType playPause) {
boolean isPlaying = PlayPauseType.PLAY.equals(command); boolean isPlaying = PlayPauseType.PLAY.equals(command);
connector.switchRadio(isPlaying); connector.switchRadio(isPlaying);
@ -161,8 +204,8 @@ public class SomneoHandler extends BaseThingHandler {
} }
break; break;
case CHANNEL_AUDIO_VOLUME: case CHANNEL_AUDIO_VOLUME:
if (command instanceof PercentType) { if (command instanceof PercentType percent) {
connector.setAudioVolume(Integer.parseInt(command.toFullString())); connector.setAudioVolume(percent.intValue());
} }
break; break;
case CHANNEL_LIGHT_MAIN: case CHANNEL_LIGHT_MAIN:
@ -177,8 +220,8 @@ public class SomneoHandler extends BaseThingHandler {
updateState(CHANNEL_SUNSET_SWITCH, OnOffType.OFF); updateState(CHANNEL_SUNSET_SWITCH, OnOffType.OFF);
} }
} }
if (command instanceof PercentType) { if (command instanceof PercentType percent) {
int level = Integer.parseInt(command.toFullString()); int level = percent.intValue();
if (level > 0) { if (level > 0) {
connector.setMainLightDimmer(level); connector.setMainLightDimmer(level);
@ -205,23 +248,23 @@ public class SomneoHandler extends BaseThingHandler {
} }
break; break;
case CHANNEL_RELAX_BREATHING_RATE: case CHANNEL_RELAX_BREATHING_RATE:
if (command instanceof DecimalType) { if (command instanceof DecimalType decimal) {
connector.setRelaxBreathingRate(Integer.parseInt(command.toFullString())); connector.setRelaxBreathingRate(decimal.intValue());
} }
break; break;
case CHANNEL_RELAX_DURATION: case CHANNEL_RELAX_DURATION:
if (command instanceof DecimalType) { if (command instanceof QuantityType quantity) {
connector.setRelaxDuration(Integer.parseInt(command.toFullString())); connector.setRelaxDuration(quantity.intValue());
} }
break; break;
case CHANNEL_RELAX_GUIDANCE_TYPE: case CHANNEL_RELAX_GUIDANCE_TYPE:
if (command instanceof DecimalType) { if (command instanceof DecimalType decimal) {
connector.setRelaxGuidanceType(Integer.parseInt(command.toFullString())); connector.setRelaxGuidanceType(decimal.intValue());
} }
break; break;
case CHANNEL_RELAX_LIGHT_INTENSITY: case CHANNEL_RELAX_LIGHT_INTENSITY:
if (command instanceof PercentType) { if (command instanceof PercentType percent) {
connector.setRelaxLightIntensity(Integer.parseInt(command.toFullString())); connector.setRelaxLightIntensity(percent.intValue());
} }
break; break;
case CHANNEL_RELAX_SWITCH: case CHANNEL_RELAX_SWITCH:
@ -241,8 +284,8 @@ public class SomneoHandler extends BaseThingHandler {
} }
break; break;
case CHANNEL_RELAX_VOLUME: case CHANNEL_RELAX_VOLUME:
if (command instanceof PercentType) { if (command instanceof PercentType percent) {
connector.setRelaxVolume(Integer.parseInt(command.toFullString())); connector.setRelaxVolume(percent.intValue());
} }
break; break;
case CHANNEL_SUNSET_AMBIENT_NOISE: case CHANNEL_SUNSET_AMBIENT_NOISE:
@ -251,18 +294,18 @@ public class SomneoHandler extends BaseThingHandler {
} }
break; break;
case CHANNEL_SUNSET_COLOR_SCHEMA: case CHANNEL_SUNSET_COLOR_SCHEMA:
if (command instanceof DecimalType) { if (command instanceof DecimalType decimal) {
connector.setSunsetColorSchema(Integer.parseInt(command.toFullString())); connector.setSunsetColorSchema(decimal.intValue());
} }
break; break;
case CHANNEL_SUNSET_DURATION: case CHANNEL_SUNSET_DURATION:
if (command instanceof DecimalType) { if (command instanceof QuantityType quantity) {
connector.setSunsetDuration(Integer.parseInt(command.toFullString())); connector.setSunsetDuration(quantity.intValue());
} }
break; break;
case CHANNEL_SUNSET_LIGHT_INTENSITY: case CHANNEL_SUNSET_LIGHT_INTENSITY:
if (command instanceof PercentType) { if (command instanceof PercentType percent) {
connector.setSunsetLightIntensity(Integer.parseInt(command.toFullString())); connector.setSunsetLightIntensity(percent.intValue());
} }
break; break;
case CHANNEL_SUNSET_SWITCH: case CHANNEL_SUNSET_SWITCH:
@ -282,8 +325,84 @@ public class SomneoHandler extends BaseThingHandler {
} }
break; break;
case CHANNEL_SUNSET_VOLUME: case CHANNEL_SUNSET_VOLUME:
if (command instanceof PercentType) { if (command instanceof PercentType percent) {
connector.setSunsetVolume(Integer.parseInt(command.toFullString())); 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; break;
default: default:
@ -391,19 +510,30 @@ public class SomneoHandler extends BaseThingHandler {
return; return;
} }
int refreshInterval = getConfigAs(SomneoConfiguration.class).refreshInterval; final SomneoConfiguration config = getConfigAs(SomneoConfiguration.class);
logger.debug("Start polling job at interval {}s", refreshInterval); 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); 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() { private void stopPolling() {
final ScheduledFuture<?> pollingJob = this.pollingJob; final ScheduledFuture<?> pollingJob = this.pollingJob;
if (pollingJob == null || pollingJob.isCancelled()) { if (pollingJob != null) {
return; 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."); logger.debug("HTTP polling stopped.");
} }
@ -414,41 +544,20 @@ public class SomneoHandler extends BaseThingHandler {
} }
try { try {
final SensorData sensorData = connector.fetchSensorData(); updateSensors();
updateState(CHANNEL_SENSOR_HUMIDITY, sensorData.getCurrentHumidity());
updateState(CHANNEL_SENSOR_ILLUMINANCE, sensorData.getCurrentIlluminance());
updateState(CHANNEL_SENSOR_NOISE, sensorData.getCurrentNoise());
updateState(CHANNEL_SENSOR_TEMPERATURE, sensorData.getCurrentTemperature());
final LightData lightData = connector.fetchLightData(); updateLights();
updateState(CHANNEL_LIGHT_MAIN, lightData.getMainLightState());
updateState(CHANNEL_LIGHT_NIGHT, lightData.getNightLightState());
lastLightBrightness = lightData.getMainLightLevel();
final SunsetData sunsetData = connector.fetchSunsetData(); updateSunset();
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());
final RelaxData relaxData = connector.fetchRelaxData(); updateRelax();
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());
final AudioData audioData = connector.fetchAudioData(); updateAudio();
updateState(CHANNEL_AUDIO_RADIO, audioData.getRadioState());
updateState(CHANNEL_AUDIO_AUX, audioData.getAuxState());
updateState(CHANNEL_AUDIO_VOLUME, audioData.getVolumeState());
updateState(CHANNEL_AUDIO_PRESET, audioData.getPresetState());
updateFrequency(); updateFrequency();
updateAlarm();
updateRemainingTimer(); updateRemainingTimer();
updateStatus(ThingStatus.ONLINE); 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 { private void updateFrequency() throws TimeoutException, InterruptedException, ExecutionException {
final SomneoHttpConnector connector = this.connector; final SomneoHttpConnector connector = this.connector;
if (connector == null) { if (connector == null) {
@ -541,4 +714,117 @@ public class SomneoHandler extends BaseThingHandler {
stopRemainingTimer(); 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;
}
} }

View File

@ -16,10 +16,13 @@ import static org.openhab.binding.somneo.internal.SomneoBindingConstants.*;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalTime;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.measure.quantity.Time;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient; 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.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus; 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.AudioData;
import org.openhab.binding.somneo.internal.model.DeviceData; import org.openhab.binding.somneo.internal.model.DeviceData;
import org.openhab.binding.somneo.internal.model.FirmwareData; 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.TimerData;
import org.openhab.binding.somneo.internal.model.WifiData; import org.openhab.binding.somneo.internal.model.WifiData;
import org.openhab.core.io.net.http.HttpUtil; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/** /**
* The {@link SomneoHttpConnector} is responsible for sending commands. * The {@link SomneoHttpConnector} is responsible for sending commands.
@ -290,11 +307,163 @@ public class SomneoHttpConnector {
return executeUrl("GET", PRESET_ENDPOINT, PresetData.class); 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) private <T> T executeUrl(String httpMethod, String endpoint, Class<T> classOfT)
throws TimeoutException, InterruptedException, ExecutionException { throws TimeoutException, InterruptedException, ExecutionException {
final String responseBody = executeUrl("GET", endpoint, (String) null); final String responseBody = executeUrl(httpMethod, endpoint, (String) null);
final T data = gson.fromJson(responseBody, classOfT); return gson.fromJson(responseBody, classOfT);
return data;
} }
private void executeUrl(String httpMethod, String endpoint, Object data) private void executeUrl(String httpMethod, String endpoint, Object data)

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -17,6 +17,8 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType; 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.State;
import org.openhab.core.types.UnDefType; import org.openhab.core.types.UnDefType;
@ -83,7 +85,7 @@ public class RelaxData {
if (durationInMin == null) { if (durationInMin == null) {
return UnDefType.NULL; return UnDefType.NULL;
} }
return new DecimalType(durationInMin); return new QuantityType<>(durationInMin, Units.MINUTE);
} }
public void setDurationInMin(int durationInMin) { public void setDurationInMin(int durationInMin) {

View File

@ -17,7 +17,9 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType; 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.types.StringType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.types.State; import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType; import org.openhab.core.types.UnDefType;
@ -87,7 +89,7 @@ public class SunsetData {
if (durationInMin == null) { if (durationInMin == null) {
return UnDefType.NULL; return UnDefType.NULL;
} }
return new DecimalType(durationInMin); return new QuantityType<>(durationInMin, Units.MINUTE);
} }
public void setDurationInMin(int durationInMin) { public void setDurationInMin(int durationInMin) {

View File

@ -1,12 +1,31 @@
# add-on # add-on
addon.somneo.name = Somneo Binding addon.somneo.name = Somneo Binding
addon.somneo.description = This is the binding for Philips Somneo devices. addon.somneo.description = This is the binding for Philips Somneo devices.
# thing types # thing types
thing-type.somneo.hf367x.label = Philips Somneo Light 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.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.label = Hostname
thing-type.config.somneo.hf367x.hostname.description = Hostname or IP address of the device. thing-type.config.somneo.hf367x.hostname.description = Hostname or IP address of the device.
thing-type.config.somneo.hf367x.ignoreSSLErrors.label = Ignore SSL Errors 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.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.label = Refresh Interval
thing-type.config.somneo.hf367x.refreshInterval.description = Interval the device is polled in sec. 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 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.label = Audio Player
channel-group-type.somneo.audio.description = Channels to control the audio player. channel-group-type.somneo.audio.description = Channels to control the audio player.
channel-group-type.somneo.audio.channel.aux.label = AUX Input 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.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.label = Light
channel-group-type.somneo.light.description = Different light channels. 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.label = Relax Breathe
channel-group-type.somneo.relax.description = Light-guided breathing helps you relax for sleep. 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.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.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.sensor.label = Sensor Data
channel-group-type.somneo.relax.channel.volume.description = Set the volume of the relax breath program. channel-group-type.somneo.sensor.description = Data from the various sensors.
channel-group-type.somneo.sunset.label = Sunset 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.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.label = Sunset Brightness
channel-group-type.somneo.sunset.channel.lightIntensity.description = The channel allows to set the light intensity. 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.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.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 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.label = Ambient Noise
channel-type.somneo.ambientNoise.description = Ambient noise played during the sunset. channel-type.somneo.ambientNoise.description = Ambient noise played during the sunset.
channel-type.somneo.ambientNoise.state.option.off = No sound 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.5 = 8 BR/min
channel-type.somneo.breathingRate.state.option.6 = 9 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.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.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.0 = Sunny day
channel-type.somneo.colorSchema.state.option.1 = Island red channel-type.somneo.colorSchema.state.option.1 = Island red
channel-type.somneo.colorSchema.state.option.2 = Nordic white 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.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.label = Noise
channel-type.somneo.noise.description = The current noise in dB. 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.label = FM Preset
channel-type.somneo.preset.description = The Device has 5 presets to store radio frequencies. channel-type.somneo.preset.description = The Device has 5 presets to store radio frequencies.
channel-type.somneo.relaxDuration.label = Duration channel-type.somneo.relaxDuration.label = Duration
channel-type.somneo.relaxDuration.description = The duration of relax breathe program in minutes. 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.5\ min = 5 Minutes
channel-type.somneo.relaxDuration.state.option.10 = 10 Minutes channel-type.somneo.relaxDuration.state.option.10\ min = 10 Minutes
channel-type.somneo.relaxDuration.state.option.15 = 15 Minutes channel-type.somneo.relaxDuration.state.option.15\ min = 15 Minutes
channel-type.somneo.remainingTime.label = Remaining Time channel-type.somneo.remainingTime.label = Remaining Time
channel-type.somneo.remainingTime.description = Remaining time from an activated program. 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.label = Duration
channel-type.somneo.sunsetDuration.description = The duration of sunset program in minutes. 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.5\ min = 5 Minutes
channel-type.somneo.sunsetDuration.state.option.10 = 10 Minutes channel-type.somneo.sunsetDuration.state.option.10\ min = 10 Minutes
channel-type.somneo.sunsetDuration.state.option.15 = 15 Minutes channel-type.somneo.sunsetDuration.state.option.15\ min = 15 Minutes
channel-type.somneo.sunsetDuration.state.option.20 = 20 Minutes channel-type.somneo.sunsetDuration.state.option.20\ min = 20 Minutes
channel-type.somneo.sunsetDuration.state.option.30 = 30 Minutes channel-type.somneo.sunsetDuration.state.option.30\ min = 30 Minutes
channel-type.somneo.sunsetDuration.state.option.45 = 45 Minutes channel-type.somneo.sunsetDuration.state.option.45\ min = 45 Minutes
channel-type.somneo.sunsetDuration.state.option.60 = 60 Minutes channel-type.somneo.sunsetDuration.state.option.60\ min = 60 Minutes
channel-type.somneo.temperature.label = Temperature channel-type.somneo.temperature.label = Temperature
channel-type.somneo.temperature.description = The current temperature in °C. 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.

View File

@ -14,8 +14,62 @@
<channel-group id="sunset" typeId="sunset"/> <channel-group id="sunset" typeId="sunset"/>
<channel-group id="relax" typeId="relax"/> <channel-group id="relax" typeId="relax"/>
<channel-group id="audio" typeId="audio"/> <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> </channel-groups>
<properties>
<property name="thingTypeVersion">1</property>
<property name="vendor">Philips</property>
</properties>
<config-description> <config-description>
<parameter name="hostname" type="text" required="true"> <parameter name="hostname" type="text" required="true">
<context>network-address</context> <context>network-address</context>
@ -34,6 +88,12 @@
<default>30</default> <default>30</default>
<advanced>true</advanced> <advanced>true</advanced>
</parameter> </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"> <parameter name="ignoreSSLErrors" type="boolean">
<label>Ignore SSL Errors</label> <label>Ignore SSL Errors</label>
<description>If set to true ignores invalid SSL certificate errors. This is potentially dangerous.</description> <description>If set to true ignores invalid SSL certificate errors. This is potentially dangerous.</description>
@ -43,6 +103,52 @@
</config-description> </config-description>
</thing-type> </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"> <channel-group-type id="audio">
<label>Audio Player</label> <label>Audio Player</label>
<description>Channels to control the audio player.</description> <description>Channels to control the audio player.</description>
@ -67,7 +173,7 @@
<description>Different light channels.</description> <description>Different light channels.</description>
<category>Light</category> <category>Light</category>
<channels> <channels>
<channel id="main" typeId="system.brightness"/> <channel id="main" typeId="brightness"/>
<channel id="night" typeId="light"/> <channel id="night" typeId="light"/>
</channels> </channels>
</channel-group-type> </channel-group-type>
@ -96,10 +202,7 @@
<channel id="breathingRate" typeId="breathingRate"/> <channel id="breathingRate" typeId="breathingRate"/>
<channel id="duration" typeId="relaxDuration"/> <channel id="duration" typeId="relaxDuration"/>
<channel id="guidanceType" typeId="guidanceType"/> <channel id="guidanceType" typeId="guidanceType"/>
<channel id="lightIntensity" typeId="system.brightness"> <channel id="lightIntensity" typeId="sunriseBrightness"/>
<label>Light Intensity</label>
<description>The channel allows to set the light intensity.</description>
</channel>
<channel id="volume" typeId="system.volume"/> <channel id="volume" typeId="system.volume"/>
</channels> </channels>
</channel-group-type> </channel-group-type>
@ -114,9 +217,9 @@
<description>The switch channel allows to turn the sunset program on or off.</description> <description>The switch channel allows to turn the sunset program on or off.</description>
</channel> </channel>
<channel id="remainingTime" typeId="remainingTime"/> <channel id="remainingTime" typeId="remainingTime"/>
<channel id="lightIntensity" typeId="system.brightness"> <channel id="lightIntensity" typeId="brightness">
<label>Light Intensity</label> <label>Sunset Brightness</label>
<description>The channel allows to set the light intensity.</description> <description>The channel allows to set the sunset light intensity.</description>
</channel> </channel>
<channel id="duration" typeId="sunsetDuration"/> <channel id="duration" typeId="sunsetDuration"/>
<channel id="colorSchema" typeId="colorSchema"/> <channel id="colorSchema" typeId="colorSchema"/>
@ -125,6 +228,80 @@
</channels> </channels>
</channel-group-type> </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"> <channel-type id="ambientNoise">
<item-type>String</item-type> <item-type>String</item-type>
<label>Ambient Noise</label> <label>Ambient Noise</label>
@ -170,10 +347,22 @@
</state> </state>
</channel-type> </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"> <channel-type id="colorSchema">
<item-type>Number</item-type> <item-type>Number</item-type>
<label>Color Schema</label> <label>Color Schema</label>
<description>Choose a personal sunset.</description> <description>Choose a personal sunrise or sunset.</description>
<category>Sunset</category> <category>Sunset</category>
<tags> <tags>
<tag>Control</tag> <tag>Control</tag>
@ -261,6 +450,29 @@
<state pattern="%d %unit%" readOnly="true"/> <state pattern="%d %unit%" readOnly="true"/>
</channel-type> </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"> <channel-type id="preset">
<item-type>String</item-type> <item-type>String</item-type>
<label>FM Preset</label> <label>FM Preset</label>
@ -282,9 +494,9 @@
</tags> </tags>
<state> <state>
<options> <options>
<option value="5">5 Minutes</option> <option value="5 min">5 Minutes</option>
<option value="10">10 Minutes</option> <option value="10 min">10 Minutes</option>
<option value="15">15 Minutes</option> <option value="15 min">15 Minutes</option>
</options> </options>
</state> </state>
</channel-type> </channel-type>
@ -301,6 +513,52 @@
<state pattern="%1$tM:%1$tS min" readOnly="true"/> <state pattern="%1$tM:%1$tS min" readOnly="true"/>
</channel-type> </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"> <channel-type id="sunsetDuration">
<item-type>Number:Time</item-type> <item-type>Number:Time</item-type>
<label>Duration</label> <label>Duration</label>
@ -312,13 +570,13 @@
</tags> </tags>
<state> <state>
<options> <options>
<option value="5">5 Minutes</option> <option value="5 min">5 Minutes</option>
<option value="10">10 Minutes</option> <option value="10 min">10 Minutes</option>
<option value="15">15 Minutes</option> <option value="15 min">15 Minutes</option>
<option value="20">20 Minutes</option> <option value="20 min">20 Minutes</option>
<option value="30">30 Minutes</option> <option value="30 min">30 Minutes</option>
<option value="45">45 Minutes</option> <option value="45 min">45 Minutes</option>
<option value="60">60 Minutes</option> <option value="60 min">60 Minutes</option>
</options> </options>
</state> </state>
</channel-type> </channel-type>

View File

@ -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>