The Philips Somneo thing requires the `hostname` it can connect to.
Its API only allows HTTPS access, but unfortunately the SSL certificate is not trusted and must be ignored by the parameter.
-| Parameter | Values | Default |
-| --------------- | ------------------------------------ | ------- |
-| hostname | Hostname or IP address of the device | - |
-| port | Port number | 443 |
-| refreshInterval | Interval the device is polled in sec | 30 |
-| ignoreSSLErrors | Ignore SSL Errors | true |
+| Parameter | Values | Default |
+| ---------------------------- | ----------------------------------------------------------- | ------- |
+| hostname | Hostname or IP address of the device | - |
+| port | Port number | 443 |
+| refreshInterval | Interval the device is polled in sec | 30 |
+| refreshIntervalAlarmExtended | Interval the device is polled in sec (alarm clock settings) | 30 |
+| ignoreSSLErrors | Ignore SSL Errors | true |
## Channels
-| Channel | Type | Read/Write | Description |
-| --------------------- | -------------------- | ---------- | ------------------------------------------------------ |
-| _Sensor_ | | | |
-| sensor#illuminance | Number:Illuminance | R | The current illuminance in lux |
-| sensor#temperature | Number:Temperature | R | The current temperature |
-| sensor#humidity | Number:Dimensionless | R | The current humidity in % |
-| sensor#noise | Number:Dimensionless | R | The current noise in dB |
-| _Light_ | | | |
-| light#main | Switch | RW | Turn the light on, off and set the brightness |
-| light#night | Switch | RW | Turn the night light on or off |
-| _Sunset_ | | | |
-| sunset#switch | Switch | RW | Turn the sunset program on or off |
-| sunset#remainingTime | Number:Time | R | Remaining time from an activated program |
-| sunset#lightIntensity | Dimmer | RW | Set the brightness during the sunset programme |
-| sunset#duration | Number:Time | RW | The duration of sunset program in minutes |
-| sunset#colorSchema | Number | RW | Choose a personal sunset |
-| sunset#ambientNoise | String | RW | Ambient noise played during the sunset |
-| sunset#volume | Dimmer | RW | Set the volume during the sunset programme |
-| _Relax_ | | | |
-| relax#switch | Switch | RW | Turn the relax breathe program on or off |
-| relax#remainingTime | Number:Time | R | Remaining time from an activated program |
-| relax#breathingRate | Number | RW | Breathing rate per minute during the relax program |
-| relax#duration | Number:Time | RW | The duration of breathe program in minutes |
-| relax#guidanceType | Number | RW | Select a breath guidance type during the relax program |
-| relax#lightIntensity | Dimmer | RW | Set the brightness during the breathe programme |
-| relax#volume | Dimmer | RW | Set the volume during the breathe programme |
-| _Audio_ | | | |
-| audio#radio | Player | RW | Controlling the radio and seeking for a frequency |
-| audio#aux | Switch | RW | Turn the AUX input on or off |
-| audio#volume | Dimmer | RW | Change the sound volume of the device |
-| audio#preset | String | RW | The Device has 5 presets to store radio frequencies |
-| audio#frequency | String | R | The currently selected radio frequency |
+| Channel | Type | Read/Write | Description |
+| ------------------------- | -------------------- | ---------- | ------------------------------------------------------- |
+| _Sensor_ | | | |
+| sensor#illuminance | Number:Illuminance | R | The current illuminance in lux |
+| sensor#temperature | Number:Temperature | R | The current temperature |
+| sensor#humidity | Number:Dimensionless | R | The current humidity in % |
+| sensor#noise | Number:Dimensionless | R | The current noise in dB |
+| _Light_ | | | |
+| light#main | Switch | RW | Turn the light on, off and set the brightness |
+| light#night | Switch | RW | Turn the night light on or off |
+| _Sunset_ | | | |
+| sunset#switch | Switch | RW | Turn the sunset program on or off |
+| sunset#remainingTime | Number:Time | R | Remaining time from an activated program |
+| sunset#lightIntensity | Dimmer | RW | Set the brightness during the sunset programme |
+| sunset#duration | Number:Time | RW | The duration of sunset program in minutes |
+| sunset#colorSchema | Number | RW | Choose a personal sunset |
+| sunset#ambientNoise | String | RW | Ambient noise played during the sunset |
+| sunset#volume | Dimmer | RW | Set the volume during the sunset programme |
+| _Relax_ | | | |
+| relax#switch | Switch | RW | Turn the relax breathe program on or off |
+| relax#remainingTime | Number:Time | R | Remaining time from an activated program |
+| relax#breathingRate | Number | RW | Breathing rate per minute during the relax program |
+| relax#duration | Number:Time | RW | The duration of breathe program in minutes |
+| relax#guidanceType | Number | RW | Select a breath guidance type during the relax program |
+| relax#lightIntensity | Dimmer | RW | Set the brightness during the breathe programme |
+| relax#volume | Dimmer | RW | Set the volume during the breathe programme |
+| _Audio_ | | | |
+| audio#radio | Player | RW | Controlling the radio and seeking for a frequency |
+| audio#aux | Switch | RW | Turn the AUX input on or off |
+| audio#volume | Dimmer | RW | Change the sound volume of the device |
+| audio#preset | String | RW | The Device has 5 presets to store radio frequencies |
+| audio#frequency | String | R | The currently selected radio frequency |
+| _Alarm_ | | | |
+| alarm#snooze | Number:Time | RW | The duration of the snooze function in minutes |
+| _Alarm[1...16]_ | | | |
+| alarm[]#configured | Switch | RW | The duration of the snooze function in minutes |
+| alarm[]#switch | Switch | RW | Turn the alarm clock on or off |
+| alarm[]#repeatDay | Number | RW | The days on which the alarm is repeated |
+| alarm[]#alarmTime | DateTime | RW | Alarm clock time |
+| alarm[]#powerWake | Switch | RW | Turn the power wake on or off |
+| alarm[]#powerWakeDelay | Number:Time | RW | How long after the normal alarm should Power Wake start |
+| alarm[]#sunriseDuration | Number:Time | RW | The duration of sunrise program in minutes |
+| alarm[]#sunriseBrightness | Dimmer | RW | The channel allows to set the sunrise light intensity |
+| alarm[]#sunriseSchema | Number | RW | Choose a personal sunrise |
+| alarm[]#sound | String | RW | The type of sound used for the alarm sound |
+| alarm[]#volume | Dimmer | RW | Change the sound volume of the alarm clock |
## Full Example
Dimmer PhilipsSomneo_AudioVolume "Volume" <SoundVolume> ["Control", "SoundVolume"] { channel="somneo:hf367x:1:audio#volume" }
String PhilipsSomneo_AudioPreset "FM Preset" ["Control"] { channel="somneo:hf367x:1:audio#preset" }
String PhilipsSomneo_AudioFrequency "FM Frequency" ["Status"] { channel="somneo:hf367x:1:audio#frequency" }
+// Alarm
+Number:Time PhilipsSomneo_AlarmSnooze "Alarm Snooze" ["Control", "Duration"] { channel="somneo:hf367x:1:alarm#snooze" }
+
+Switch PhilipsSomneo_Alarm1Switch "Alarm Clock" ["Switch", "Power"] { channel="somneo:hf367x:1:alarm1#switch" }
+DateTime PhilipsSomneo_Alarm1Time "Alarm Clock Time" <Time> ["Control"] { channel="somneo:hf367x:1:alarm1#alarmTime" }
+Number PhilipsSomneo_Alarm1RepeatDay "Repeat on [JS(somneorepeatday.js):%s]" <calendar> ["Control"] { channel="somneo:hf367x:1:alarm1#repeatDay" }
+Switch PhilipsSomneo_Alarm1PowerWake "Power Wake" ["Control"] { channel="somneo:hf367x:1:alarm1#powerWake" }
+Number:Time PhilipsSomneo_Alarm1PowerWakeDelay "Power Wake Delay" <Time> ["Control", "Duration"] { channel="somneo:hf367x:1:alarm1#powerWakeDelay" }
+Number:Time PhilipsSomneo_Alarm1SunriseDuration "Sunrise Duration" <Time> ["Control", "Duration"] { channel="somneo:hf367x:1:alarm1#sunriseDuration" }
+Dimmer PhilipsSomneo_Alarm1SunriseBrightness "Sunrise Brightness" <Light> ["Control", "Light"] { channel="somneo:hf367x:1:alarm1#sunriseBrightness" }
+Number PhilipsSomneo_Alarm1SunriseSchema "Sunrise Color" <sunrise> ["Control", "ColorTemperature"] { channel="somneo:hf367x:1:alarm1#sunriseSchema" }
+String PhilipsSomneo_Alarm1Sound "Sound" ["Control"] { channel="somneo:hf367x:1:alarm1#sound" }
+Dimmer PhilipsSomneo_Alarm1Volume "Volume" <SoundVolume> ["Control", "SoundVolume"] { channel="somneo:hf367x:1:alarm1#volume" }
+```
+
+transform/somneorepeatday.js
+```javascript
+(function(i) {
+ if (i == 254) {
+ return "Daily";
+ }
+ if (i == 192) {
+ return "Weekend";
+ }
+ if (i == 62) {
+ return "Weekdays";
+ }
+ days = [];
+ [
+ ["Sunday", 128],
+ ["Saturday", 64],
+ ["Friday", 32],
+ ["Thursday", 16],
+ ["Wednesday", 8],
+ ["Tuesday", 4],
+ ["Monday", 2]
+ ].forEach(function (x) {
+ if (i >= x[1]) {
+ days.push(x[0]);
+ i = i % x[1];
+ }
+ });
+
+ if (days.length === 0) {
+ return "Never";
+ }
+ if (days.length == 1) {
+ return days[0];
+ }
+ return days.reverse().map(function(x) {
+ return x.slice(0, 2);
+ }).join(" ");
+})(input)
```
somneo.sitemap:
Default item=PhilipsSomneo_AudioPreset visibility=[PhilipsSomneo_AudioRadio==PLAY]
Default item=PhilipsSomneo_AudioFrequency visibility=[PhilipsSomneo_AudioRadio==PLAY]
}
+ Frame label="Alarm Common" {
+ Setpoint item=PhilipsSomneo_AlarmSnooze minValue=1 maxValue=20
+ Text label="Alarms" icon="settings" {
+ Default item=PhilipsSomneo_Alarm3Configured
+ Default item=PhilipsSomneo_Alarm4Configured
+ Default item=PhilipsSomneo_Alarm5Configured
+ Default item=PhilipsSomneo_Alarm6Configured
+ Default item=PhilipsSomneo_Alarm7Configured
+ Default item=PhilipsSomneo_Alarm8Configured
+ Default item=PhilipsSomneo_Alarm9Configured
+ Default item=PhilipsSomneo_Alarm10Configured
+ Default item=PhilipsSomneo_Alarm11Configured
+ Default item=PhilipsSomneo_Alarm12Configured
+ Default item=PhilipsSomneo_Alarm13Configured
+ Default item=PhilipsSomneo_Alarm14Configured
+ Default item=PhilipsSomneo_Alarm15Configured
+ Default item=PhilipsSomneo_Alarm16Configured
+ }
+ }
+ Frame label="Alarm [1]" {
+ Default item=PhilipsSomneo_Alarm1Switch
+ Default item=PhilipsSomneo_Alarm1Time
+ Default item=PhilipsSomneo_Alarm1PowerWake
+ Slider item=PhilipsSomneo_Alarm1PowerWakeDelay minValue=0 maxValue=59
+ Slider item=PhilipsSomneo_Alarm1RepeatDay minValue=0 maxValue=254 step=2
+ Text label="Settings" icon="settings" {
+ Default item=PhilipsSomneo_Alarm1SunriseDuration
+ Slider item=PhilipsSomneo_Alarm1SunriseBrightness
+ Selection item=PhilipsSomneo_Alarm1SunriseSchema
+ Default item=PhilipsSomneo_Alarm1Sound
+ Default item=PhilipsSomneo_Alarm1Volume
+ }
+ }
+ Frame label="Alarm [2]"{
+ Default item=PhilipsSomneo_Alarm2Switch
+ Default item=PhilipsSomneo_Alarm2Time
+ Default item=PhilipsSomneo_Alarm2PowerWake
+ Slider item=PhilipsSomneo_Alarm2PowerWakeDelay minValue=0 maxValue=59
+ Slider item=PhilipsSomneo_Alarm2RepeatDay minValue=0 maxValue=254 step=2
+ Text label="Settings" icon="settings" {
+ Default item=PhilipsSomneo_Alarm2SunriseDuration
+ Slider item=PhilipsSomneo_Alarm2SunriseBrightness minValue=4 maxValue=100 step=4
+ Selection item=PhilipsSomneo_Alarm2SunriseSchema
+ Default item=PhilipsSomneo_Alarm2Sound
+ Slider item=PhilipsSomneo_Alarm2Volume minValue=4 maxValue=100 step=4
+ }
+ }
+ Frame label="Alarm [3]" visibility=[PhilipsSomneo_Alarm3Configured==ON] {
+ Default item=PhilipsSomneo_Alarm3Switch
+ Default item=PhilipsSomneo_Alarm3Time
+ Default item=PhilipsSomneo_Alarm3PowerWake
+ Slider item=PhilipsSomneo_Alarm3PowerWakeDelay minValue=0 maxValue=59
+ Slider item=PhilipsSomneo_Alarm3RepeatDay minValue=0 maxValue=254 step=2
+ Text label="Settings" icon="settings" {
+ Default item=PhilipsSomneo_Alarm3SunriseDuration
+ Slider item=PhilipsSomneo_Alarm3SunriseBrightness minValue=4 maxValue=100 step=4
+ Selection item=PhilipsSomneo_Alarm3SunriseSchema
+ Default item=PhilipsSomneo_Alarm3Sound
+ Slider item=PhilipsSomneo_Alarm3Volume minValue=4 maxValue=100 step=4
+ }
+ }
+ Frame label="Alarm [4]" visibility=[PhilipsSomneo_Alarm4Configured==ON] {
+ Default item=PhilipsSomneo_Alarm4Switch
+ Default item=PhilipsSomneo_Alarm4Time
+ Default item=PhilipsSomneo_Alarm4PowerWake
+ Slider item=PhilipsSomneo_Alarm4PowerWakeDelay minValue=0 maxValue=59
+ Slider item=PhilipsSomneo_Alarm4RepeatDay minValue=0 maxValue=254 step=2
+ Text label="Settings" icon="settings" {
+ Default item=PhilipsSomneo_Alarm4SunriseDuration
+ Slider item=PhilipsSomneo_Alarm4SunriseBrightness minValue=4 maxValue=100 step=4
+ Selection item=PhilipsSomneo_Alarm4SunriseSchema
+ Default item=PhilipsSomneo_Alarm4Sound
+ Slider item=PhilipsSomneo_Alarm4Volume minValue=4 maxValue=100 step=4
+ }
+ }
}
```
public static final String CHANNEL_SUNSET_REMAINING_TIME = "sunset#remainingTime";
public static final String CHANNEL_SUNSET_SWITCH = "sunset#switch";
public static final String CHANNEL_SUNSET_VOLUME = "sunset#volume";
+ public static final String CHANNEL_ALARM_SNOOZE = "alarm#snooze";
+ public static final String CHANNEL_ALARM_CONFIGURED = "alarm%d#configured";
+ public static final String CHANNEL_ALARM_SWITCH = "alarm%d#switch";
+ public static final String CHANNEL_ALARM_TIME = "alarm%d#alarmTime";
+ public static final String CHANNEL_ALARM_REPEAT_DAY = "alarm%d#repeatDay";
+ public static final String CHANNEL_ALARM_POWER_WAKE = "alarm%d#powerWake";
+ public static final String CHANNEL_ALARM_POWER_WAKE_DELAY = "alarm%d#powerWakeDelay";
+ public static final String CHANNEL_ALARM_SUNRISE_DURATION = "alarm%d#sunriseDuration";
+ public static final String CHANNEL_ALARM_SUNRISE_BRIGHTNESS = "alarm%d#sunriseBrightness";
+ public static final String CHANNEL_ALARM_SUNRISE_SCHEMA = "alarm%d#sunriseSchema";
+ public static final String CHANNEL_ALARM_SOUND = "alarm%d#sound";
+ public static final String CHANNEL_ALARM_VOLUME = "alarm%d#volume";
+
+ // Regex for alarm channels
+ public static final String CHANNEL_ALARM_PREFIX_REGEX = "^alarm(\\d{1,2})#\\w+$";
// List of all Web Service Endpoints
public static final String AUDIO_ENDPOINT = "/1/wuply";
public static final String SENSORS_ENDPOINT = "/1/wusrd";
public static final String SUNSET_ENDPOINT = "/1/wudsk";
public static final String WIFI_ENDPOINT = "/0/wifi";
+ public static final String ALARM_STATES_ENDPOINT = "/1/wualm/aenvs";
+ public static final String ALARM_SCHEDULES_ENDPOINT = "/1/wualm/aalms";
+ public static final String ALARM_SETTINGS_ENDPOINT = "/1/wualm";
+ public static final String ALARM_EDIT_ENDPOINT = "/1/wualm/prfwu";
}
public String hostname = "";
public int port = 443;
public int refreshInterval = 30;
+ public int refreshIntervalAlarmExtended = 300;
public boolean ignoreSSLErrors = false;
}
import java.io.EOFException;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.somneo.internal.model.AlarmSchedulesData;
+import org.openhab.binding.somneo.internal.model.AlarmSettingsData;
+import org.openhab.binding.somneo.internal.model.AlarmStateData;
import org.openhab.binding.somneo.internal.model.AudioData;
import org.openhab.binding.somneo.internal.model.DeviceData;
import org.openhab.binding.somneo.internal.model.FirmwareData;
import org.openhab.binding.somneo.internal.model.SunsetData;
import org.openhab.binding.somneo.internal.model.TimerData;
import org.openhab.binding.somneo.internal.model.WifiData;
+import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.NextPreviousType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
+import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final SomneoPresetStateDescriptionProvider provider;
+ private final Pattern alarmPattern;
+
/**
* Job to poll data from the device.
*/
private @Nullable ScheduledFuture<?> pollingJob;
+ private @Nullable ScheduledFuture<?> pollingJobExtended;
/**
* Job to count down the remaining program time.
super(thing);
this.httpClientProvider = httpClientProvider;
this.provider = provider;
+ this.alarmPattern = Objects.requireNonNull(Pattern.compile(CHANNEL_ALARM_PREFIX_REGEX));
}
@Override
String channelId = channelUID.getId();
logger.debug("Handle command '{}' for channel {}", command, channelId);
- if (command instanceof RefreshType) {
- this.poll();
- return;
- }
+ try {
+ final SomneoHttpConnector connector = this.connector;
+ if (connector == null) {
+ return;
+ }
- 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;
+ }
- try {
switch (channelId) {
case CHANNEL_AUDIO_AUX:
- if (command instanceof OnOffType) {
+ if (command instanceof OnOffType onOff) {
boolean isOn = OnOffType.ON.equals(command);
connector.switchAux(isOn);
}
break;
case CHANNEL_AUDIO_RADIO:
- if (command instanceof PlayPauseType) {
+ if (command instanceof PlayPauseType playPause) {
boolean isPlaying = PlayPauseType.PLAY.equals(command);
connector.switchRadio(isPlaying);
}
break;
case CHANNEL_AUDIO_VOLUME:
- if (command instanceof PercentType) {
- connector.setAudioVolume(Integer.parseInt(command.toFullString()));
+ if (command instanceof PercentType percent) {
+ connector.setAudioVolume(percent.intValue());
}
break;
case CHANNEL_LIGHT_MAIN:
updateState(CHANNEL_SUNSET_SWITCH, OnOffType.OFF);
}
}
- if (command instanceof PercentType) {
- int level = Integer.parseInt(command.toFullString());
+ if (command instanceof PercentType percent) {
+ int level = percent.intValue();
if (level > 0) {
connector.setMainLightDimmer(level);
}
break;
case CHANNEL_RELAX_BREATHING_RATE:
- if (command instanceof DecimalType) {
- connector.setRelaxBreathingRate(Integer.parseInt(command.toFullString()));
+ if (command instanceof DecimalType decimal) {
+ connector.setRelaxBreathingRate(decimal.intValue());
}
break;
case CHANNEL_RELAX_DURATION:
- if (command instanceof DecimalType) {
- connector.setRelaxDuration(Integer.parseInt(command.toFullString()));
+ if (command instanceof QuantityType quantity) {
+ connector.setRelaxDuration(quantity.intValue());
}
break;
case CHANNEL_RELAX_GUIDANCE_TYPE:
- if (command instanceof DecimalType) {
- connector.setRelaxGuidanceType(Integer.parseInt(command.toFullString()));
+ if (command instanceof DecimalType decimal) {
+ connector.setRelaxGuidanceType(decimal.intValue());
}
break;
case CHANNEL_RELAX_LIGHT_INTENSITY:
- if (command instanceof PercentType) {
- connector.setRelaxLightIntensity(Integer.parseInt(command.toFullString()));
+ if (command instanceof PercentType percent) {
+ connector.setRelaxLightIntensity(percent.intValue());
}
break;
case CHANNEL_RELAX_SWITCH:
}
break;
case CHANNEL_RELAX_VOLUME:
- if (command instanceof PercentType) {
- connector.setRelaxVolume(Integer.parseInt(command.toFullString()));
+ if (command instanceof PercentType percent) {
+ connector.setRelaxVolume(percent.intValue());
}
break;
case CHANNEL_SUNSET_AMBIENT_NOISE:
}
break;
case CHANNEL_SUNSET_COLOR_SCHEMA:
- if (command instanceof DecimalType) {
- connector.setSunsetColorSchema(Integer.parseInt(command.toFullString()));
+ if (command instanceof DecimalType decimal) {
+ connector.setSunsetColorSchema(decimal.intValue());
}
break;
case CHANNEL_SUNSET_DURATION:
- if (command instanceof DecimalType) {
- connector.setSunsetDuration(Integer.parseInt(command.toFullString()));
+ if (command instanceof QuantityType quantity) {
+ connector.setSunsetDuration(quantity.intValue());
}
break;
case CHANNEL_SUNSET_LIGHT_INTENSITY:
- if (command instanceof PercentType) {
- connector.setSunsetLightIntensity(Integer.parseInt(command.toFullString()));
+ if (command instanceof PercentType percent) {
+ connector.setSunsetLightIntensity(percent.intValue());
}
break;
case CHANNEL_SUNSET_SWITCH:
}
break;
case CHANNEL_SUNSET_VOLUME:
- if (command instanceof PercentType) {
- connector.setSunsetVolume(Integer.parseInt(command.toFullString()));
+ if (command instanceof PercentType percent) {
+ connector.setSunsetVolume(percent.intValue());
+ }
+ break;
+ case CHANNEL_ALARM_SNOOZE:
+ if (command instanceof QuantityType quantity) {
+ connector.setAlarmSnooze(quantity.intValue());
+ }
+ break;
+ case CHANNEL_ALARM_CONFIGURED:
+ if (alarmPosition > 2) {
+ if (command instanceof OnOffType onOff) {
+ connector.toggleAlarmConfiguration(alarmPosition, onOff);
+
+ if (OnOffType.ON.equals(command)) {
+ updateAlarmExtended(alarmPosition);
+ } else {
+ resetAlarm(alarmPosition);
+ }
+ }
+ } else {
+ logger.info("Alarm 1 and 2 can not be unset");
+ }
+ break;
+ case CHANNEL_ALARM_SWITCH:
+ if (command instanceof OnOffType onOff) {
+ connector.toggleAlarm(alarmPosition, onOff);
+ updateAlarmExtended(alarmPosition);
+ }
+ break;
+ case CHANNEL_ALARM_TIME:
+ if (command instanceof DateTimeType decimal) {
+ connector.setAlarmTime(alarmPosition, decimal);
+ }
+ break;
+ case CHANNEL_ALARM_REPEAT_DAY:
+ if (command instanceof DecimalType decimal) {
+ connector.setAlarmRepeatDay(alarmPosition, decimal);
+ }
+ break;
+ case CHANNEL_ALARM_POWER_WAKE:
+ if (command instanceof OnOffType onOff) {
+ connector.toggleAlarmPowerWake(alarmPosition, onOff);
+ if (OnOffType.OFF.equals(command)) {
+ updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE_DELAY, alarmPosition),
+ QuantityType.valueOf(0, Units.MINUTE));
+ }
+ }
+ break;
+ case CHANNEL_ALARM_POWER_WAKE_DELAY:
+ if (command instanceof QuantityType quantity) {
+ connector.setAlarmPowerWakeDelay(alarmPosition, quantity);
+ updateState(formatAlarmChannelIdByIndex(CHANNEL_ALARM_POWER_WAKE, alarmPosition), OnOffType.ON);
+ }
+ break;
+ case CHANNEL_ALARM_SUNRISE_DURATION:
+ if (command instanceof QuantityType quantity) {
+ connector.setAlarmSunriseDuration(alarmPosition, quantity);
+ }
+ break;
+ case CHANNEL_ALARM_SUNRISE_BRIGHTNESS:
+ if (command instanceof PercentType percent) {
+ connector.setAlarmSunriseBrightness(alarmPosition, percent);
+ }
+ break;
+ case CHANNEL_ALARM_SUNRISE_SCHEMA:
+ if (command instanceof DecimalType decimal) {
+ connector.setAlarmSunriseSchema(alarmPosition, decimal);
+ }
+ break;
+ case CHANNEL_ALARM_SOUND:
+ if (command instanceof StringType) {
+ connector.setAlarmSound(alarmPosition, (StringType) command);
+ }
+ break;
+ case CHANNEL_ALARM_VOLUME:
+ if (command instanceof PercentType percent) {
+ connector.setAlarmVolume(alarmPosition, percent);
}
break;
default:
return;
}
- int refreshInterval = getConfigAs(SomneoConfiguration.class).refreshInterval;
- logger.debug("Start polling job at interval {}s", refreshInterval);
+ final SomneoConfiguration config = getConfigAs(SomneoConfiguration.class);
+ final int refreshInterval = config.refreshInterval;
+ logger.debug("Start default polling job at interval {}s", refreshInterval);
this.pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, refreshInterval, TimeUnit.SECONDS);
+
+ final int refreshIntervalAlarmExtended = config.refreshIntervalAlarmExtended;
+ logger.debug("Start extended alarm polling job at interval {}s", refreshIntervalAlarmExtended);
+ this.pollingJobExtended = scheduler.scheduleWithFixedDelay(this::pollAlarmExtended, 0,
+ refreshIntervalAlarmExtended, TimeUnit.SECONDS);
}
private void stopPolling() {
final ScheduledFuture<?> pollingJob = this.pollingJob;
- if (pollingJob == null || pollingJob.isCancelled()) {
- return;
+ if (pollingJob != null) {
+ pollingJob.cancel(true);
+ this.pollingJob = null;
+ }
+
+ final ScheduledFuture<?> pollingJobExtended = this.pollingJobExtended;
+ if (pollingJobExtended != null) {
+ pollingJobExtended.cancel(true);
+ this.pollingJobExtended = null;
}
- pollingJob.cancel(true);
- this.pollingJob = null;
logger.debug("HTTP polling stopped.");
}
}
try {
- final SensorData sensorData = connector.fetchSensorData();
- updateState(CHANNEL_SENSOR_HUMIDITY, sensorData.getCurrentHumidity());
- updateState(CHANNEL_SENSOR_ILLUMINANCE, sensorData.getCurrentIlluminance());
- updateState(CHANNEL_SENSOR_NOISE, sensorData.getCurrentNoise());
- updateState(CHANNEL_SENSOR_TEMPERATURE, sensorData.getCurrentTemperature());
-
- final LightData lightData = connector.fetchLightData();
- updateState(CHANNEL_LIGHT_MAIN, lightData.getMainLightState());
- updateState(CHANNEL_LIGHT_NIGHT, lightData.getNightLightState());
- lastLightBrightness = lightData.getMainLightLevel();
-
- 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());
-
- 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());
-
- 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());
+ updateSensors();
+
+ updateLights();
+
+ updateSunset();
+
+ updateRelax();
+
+ updateAudio();
updateFrequency();
+ updateAlarm();
+
updateRemainingTimer();
updateStatus(ThingStatus.ONLINE);
}
}
+ private void updateAudio() throws TimeoutException, InterruptedException, ExecutionException {
+ final SomneoHttpConnector connector = this.connector;
+ if (connector == null) {
+ return;
+ }
+ final AudioData audioData = connector.fetchAudioData();
+ updateState(CHANNEL_AUDIO_RADIO, audioData.getRadioState());
+ updateState(CHANNEL_AUDIO_AUX, audioData.getAuxState());
+ updateState(CHANNEL_AUDIO_VOLUME, audioData.getVolumeState());
+ updateState(CHANNEL_AUDIO_PRESET, audioData.getPresetState());
+ }
+
+ private void updateRelax() throws TimeoutException, InterruptedException, ExecutionException {
+ final SomneoHttpConnector connector = this.connector;
+ if (connector == null) {
+ return;
+ }
+ final RelaxData relaxData = connector.fetchRelaxData();
+ updateState(CHANNEL_RELAX_SWITCH, relaxData.getSwitchState());
+ updateState(CHANNEL_RELAX_BREATHING_RATE, relaxData.getBreathingRate());
+ updateState(CHANNEL_RELAX_DURATION, relaxData.getDurationInMin());
+ updateState(CHANNEL_RELAX_GUIDANCE_TYPE, relaxData.getGuidanceType());
+ updateState(CHANNEL_RELAX_LIGHT_INTENSITY, relaxData.getLightIntensity());
+ updateState(CHANNEL_RELAX_VOLUME, relaxData.getSoundVolume());
+ }
+
+ private void updateSunset() throws TimeoutException, InterruptedException, ExecutionException {
+ final SomneoHttpConnector connector = this.connector;
+ if (connector == null) {
+ return;
+ }
+ final SunsetData sunsetData = connector.fetchSunsetData();
+ updateState(CHANNEL_SUNSET_SWITCH, sunsetData.getSwitchState());
+ updateState(CHANNEL_SUNSET_LIGHT_INTENSITY, sunsetData.getLightIntensity());
+ updateState(CHANNEL_SUNSET_DURATION, sunsetData.getDurationInMin());
+ updateState(CHANNEL_SUNSET_COLOR_SCHEMA, sunsetData.getColorSchema());
+ updateState(CHANNEL_SUNSET_AMBIENT_NOISE, sunsetData.getAmbientNoise());
+ updateState(CHANNEL_SUNSET_VOLUME, sunsetData.getSoundVolume());
+ }
+
+ private void updateLights() throws TimeoutException, InterruptedException, ExecutionException {
+ final SomneoHttpConnector connector = this.connector;
+ if (connector == null) {
+ return;
+ }
+ final LightData lightData = connector.fetchLightData();
+ updateState(CHANNEL_LIGHT_MAIN, lightData.getMainLightState());
+ updateState(CHANNEL_LIGHT_NIGHT, lightData.getNightLightState());
+ lastLightBrightness = lightData.getMainLightLevel();
+ }
+
+ private void updateSensors() throws TimeoutException, InterruptedException, ExecutionException {
+ final SomneoHttpConnector connector = this.connector;
+ if (connector == null) {
+ return;
+ }
+
+ final SensorData sensorData = connector.fetchSensorData();
+ updateState(CHANNEL_SENSOR_HUMIDITY, sensorData.getCurrentHumidity());
+ updateState(CHANNEL_SENSOR_ILLUMINANCE, sensorData.getCurrentIlluminance());
+ updateState(CHANNEL_SENSOR_NOISE, sensorData.getCurrentNoise());
+ updateState(CHANNEL_SENSOR_TEMPERATURE, sensorData.getCurrentTemperature());
+ }
+
private void updateFrequency() throws TimeoutException, InterruptedException, ExecutionException {
final SomneoHttpConnector connector = this.connector;
if (connector == null) {
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;
+ }
}
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
+import java.time.LocalTime;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import javax.measure.quantity.Time;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
+import org.openhab.binding.somneo.internal.model.AlarmSchedulesData;
+import org.openhab.binding.somneo.internal.model.AlarmSettingsData;
+import org.openhab.binding.somneo.internal.model.AlarmStateData;
import org.openhab.binding.somneo.internal.model.AudioData;
import org.openhab.binding.somneo.internal.model.DeviceData;
import org.openhab.binding.somneo.internal.model.FirmwareData;
import org.openhab.binding.somneo.internal.model.TimerData;
import org.openhab.binding.somneo.internal.model.WifiData;
import org.openhab.core.io.net.http.HttpUtil;
+import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.library.types.DecimalType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.types.State;
+import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
/**
* The {@link SomneoHttpConnector} is responsible for sending commands.
return executeUrl("GET", PRESET_ENDPOINT, PresetData.class);
}
- private <T> T executeUrl(String httpMethod, String endpoint, Class<T> classOfT)
+ public AlarmStateData fetchAlarmStateData() throws TimeoutException, InterruptedException, ExecutionException {
+ return executeUrl("GET", ALARM_STATES_ENDPOINT, AlarmStateData.class);
+ }
+
+ public AlarmSchedulesData fetchAlarmScheduleData()
throws TimeoutException, InterruptedException, ExecutionException {
- final String responseBody = executeUrl("GET", endpoint, (String) null);
- final T data = gson.fromJson(responseBody, classOfT);
+ return executeUrl("GET", ALARM_SCHEDULES_ENDPOINT, AlarmSchedulesData.class);
+ }
+
+ public AlarmSettingsData fetchAlarmSettingsData(final int position)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final String responseBody = executeUrl("PUT", ALARM_SETTINGS_ENDPOINT, "{\"prfnr\":" + (position) + "}");
+ AlarmSettingsData data = (AlarmSettingsData) gson.fromJson(responseBody, AlarmSettingsData.class);
+ if (data == null) {
+ return new AlarmSettingsData();
+ }
return data;
}
+ public State fetchSnoozeDuration() throws TimeoutException, InterruptedException, ExecutionException {
+ final JsonObject response = executeUrl("GET", ALARM_SETTINGS_ENDPOINT, JsonObject.class);
+ final JsonElement snooze = response.get("snztm");
+ if (snooze == null) {
+ return UnDefType.NULL;
+ }
+ return new QuantityType<>(snooze.getAsInt(), Units.MINUTE);
+ }
+
+ public void setAlarmSnooze(int snooze) throws TimeoutException, InterruptedException, ExecutionException {
+ final JsonObject data = new JsonObject();
+ data.addProperty("snztm", snooze);
+ executeUrl("PUT", ALARM_SETTINGS_ENDPOINT, data);
+ }
+
+ public void toggleAlarmConfiguration(int position, OnOffType command)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = AlarmSettingsData.withDefaultValues(position);
+
+ if (OnOffType.ON.equals(command)) {
+ final LocalTime now = LocalTime.now();
+ if (now == null) {
+ return;
+ }
+
+ data.setConfigured(true);
+ data.setEnabled(true);
+ data.setAlarmTime(now);
+ data.setRepeatDay(0);
+ } else {
+ data.setConfigured(false);
+ data.setEnabled(false);
+ }
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void toggleAlarm(int position, OnOffType enabled)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = new AlarmSettingsData();
+ data.setPosition(position);
+ data.setEnabledState(enabled);
+ if (OnOffType.ON.equals(enabled)) {
+ data.setConfigured(true);
+ }
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmTime(int position, DateTimeType time)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = fetchAlarmSettingsData(position);
+ data.setConfigured(true);
+ data.setAlarmTime(time);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmRepeatDay(int position, DecimalType days)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = new AlarmSettingsData();
+ data.setPosition(position);
+ data.setConfigured(true);
+ data.setRepeatDayState(days);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void toggleAlarmPowerWake(int position, OnOffType state)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = fetchAlarmSettingsData(position);
+ data.setPosition(position);
+ data.setPowerWakeState(state);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmPowerWakeDelay(int position, QuantityType<Time> time)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = fetchAlarmSettingsData(position);
+ data.setConfigured(true);
+ data.setPowerWakeDelayState(time);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmSunriseDuration(int position, QuantityType<Time> duration)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = new AlarmSettingsData();
+ data.setPosition(position);
+ data.setConfigured(true);
+ data.setSunriseDurationState(duration);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmSunriseBrightness(int position, PercentType percent)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = new AlarmSettingsData();
+ data.setPosition(position);
+ data.setConfigured(true);
+ data.setSunriseBrightnessState(percent);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmSunriseSchema(int position, DecimalType schema)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = new AlarmSettingsData();
+ data.setPosition(position);
+ data.setConfigured(true);
+ data.setSunriseSchemaState(schema);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmSound(int position, StringType sound)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = new AlarmSettingsData();
+ data.setPosition(position);
+ data.setConfigured(true);
+ data.setAlarmSoundState(sound);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ public void setAlarmVolume(int position, PercentType volume)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final AlarmSettingsData data = new AlarmSettingsData();
+ data.setPosition(position);
+ data.setConfigured(true);
+ data.setAlarmVolumeState(volume);
+
+ executeUrl("PUT", ALARM_EDIT_ENDPOINT, data);
+ }
+
+ private <T> T executeUrl(String httpMethod, String endpoint, Class<T> classOfT)
+ throws TimeoutException, InterruptedException, ExecutionException {
+ final String responseBody = executeUrl(httpMethod, endpoint, (String) null);
+ return gson.fromJson(responseBody, classOfT);
+ }
+
private void executeUrl(String httpMethod, String endpoint, Object data)
throws TimeoutException, InterruptedException, ExecutionException {
final String content = gson.toJson(data);
--- /dev/null
+/**
+ * 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);
+ }
+}
--- /dev/null
+/**
+ * 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;
+ }
+}
--- /dev/null
+/**
+ * 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();
+ }
+}
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.Units;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
if (durationInMin == null) {
return UnDefType.NULL;
}
- return new DecimalType(durationInMin);
+ return new QuantityType<>(durationInMin, Units.MINUTE);
}
public void setDurationInMin(int durationInMin) {
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;
if (durationInMin == null) {
return UnDefType.NULL;
}
- return new DecimalType(durationInMin);
+ return new QuantityType<>(durationInMin, Units.MINUTE);
}
public void setDurationInMin(int durationInMin) {
# add-on
+
addon.somneo.name = Somneo Binding
addon.somneo.description = This is the binding for Philips Somneo devices.
# thing types
+
thing-type.somneo.hf367x.label = Philips Somneo Light
thing-type.somneo.hf367x.description = A smart sleep and wake-up light with sensors.
+thing-type.somneo.hf367x.group.alarm1.label = Alarm 1
+thing-type.somneo.hf367x.group.alarm10.label = Alarm 10
+thing-type.somneo.hf367x.group.alarm11.label = Alarm 11
+thing-type.somneo.hf367x.group.alarm12.label = Alarm 12
+thing-type.somneo.hf367x.group.alarm13.label = Alarm 13
+thing-type.somneo.hf367x.group.alarm14.label = Alarm 14
+thing-type.somneo.hf367x.group.alarm15.label = Alarm 15
+thing-type.somneo.hf367x.group.alarm16.label = Alarm 16
+thing-type.somneo.hf367x.group.alarm2.label = Alarm 2
+thing-type.somneo.hf367x.group.alarm3.label = Alarm 3
+thing-type.somneo.hf367x.group.alarm4.label = Alarm 4
+thing-type.somneo.hf367x.group.alarm5.label = Alarm 5
+thing-type.somneo.hf367x.group.alarm6.label = Alarm 6
+thing-type.somneo.hf367x.group.alarm7.label = Alarm 7
+thing-type.somneo.hf367x.group.alarm8.label = Alarm 8
+thing-type.somneo.hf367x.group.alarm9.label = Alarm 9
+
+# thing types config
-# thing type config description
thing-type.config.somneo.hf367x.hostname.label = Hostname
thing-type.config.somneo.hf367x.hostname.description = Hostname or IP address of the device.
thing-type.config.somneo.hf367x.ignoreSSLErrors.label = Ignore SSL Errors
thing-type.config.somneo.hf367x.port.description = HTTP Port used for communication. Normally shouldn't be changed.
thing-type.config.somneo.hf367x.refreshInterval.label = Refresh Interval
thing-type.config.somneo.hf367x.refreshInterval.description = Interval the device is polled in sec.
+thing-type.config.somneo.hf367x.refreshIntervalAlarmExtended.label = Refresh Interval for extended alarm clock settings
+thing-type.config.somneo.hf367x.refreshIntervalAlarmExtended.description = Interval the device is polled in seconds. This polling triggers a sync icon on the device.
# channel group types
+
+channel-group-type.somneo.alarm.label = Alarm Clock
+channel-group-type.somneo.alarm.description = Channels to control alarm clock.
+channel-group-type.somneo.alarmCommon.label = Common Alarm Clock Settings
+channel-group-type.somneo.alarmCommon.description = Channels to control alarm clock settings that affect all alarm clocks.
+channel-group-type.somneo.alarmErasable.label = Alarm Clock
+channel-group-type.somneo.alarmErasable.description = Channels to control alarm clock.
channel-group-type.somneo.audio.label = Audio Player
channel-group-type.somneo.audio.description = Channels to control the audio player.
channel-group-type.somneo.audio.channel.aux.label = AUX Input
channel-group-type.somneo.audio.channel.radio.description = Remote control for controlling the radio and seeking for a frequency.
channel-group-type.somneo.light.label = Light
channel-group-type.somneo.light.description = Different light channels.
-channel-group-type.somneo.sensor.label = Sensor Data
-channel-group-type.somneo.sensor.description = Data from the various sensors.
channel-group-type.somneo.relax.label = Relax Breathe
channel-group-type.somneo.relax.description = Light-guided breathing helps you relax for sleep.
-channel-group-type.somneo.relax.channel.lightIntensity.label = Light Intensity
-channel-group-type.somneo.relax.channel.lightIntensity.description = The channel allows to set the light intensity.
channel-group-type.somneo.relax.channel.switch.label = Relax Breathe Program
channel-group-type.somneo.relax.channel.switch.description = The switch channel allows to turn the relax breathe program on or off.
-channel-group-type.somneo.relax.channel.volume.label = Volume
-channel-group-type.somneo.relax.channel.volume.description = Set the volume of the relax breath program.
+channel-group-type.somneo.sensor.label = Sensor Data
+channel-group-type.somneo.sensor.description = Data from the various sensors.
channel-group-type.somneo.sunset.label = Sunset
channel-group-type.somneo.sunset.description = Simulate a sunset with selectable lights and sounds.
-channel-group-type.somneo.sunset.channel.lightIntensity.label = Light Intensity
-channel-group-type.somneo.sunset.channel.lightIntensity.description = The channel allows to set the light intensity.
+channel-group-type.somneo.sunset.channel.lightIntensity.label = Sunset Brightness
+channel-group-type.somneo.sunset.channel.lightIntensity.description = The channel allows to set the sunset light intensity.
channel-group-type.somneo.sunset.channel.switch.label = Sunset Program
channel-group-type.somneo.sunset.channel.switch.description = The switch channel allows to turn the sunset program on or off.
-channel-group-type.somneo.sunset.channel.volume.label = Volume
-channel-group-type.somneo.sunset.channel.volume.description = Set the volume of the sunset program.
# channel types
+
+channel-type.somneo.alarmConfigured.label = Configured
+channel-type.somneo.alarmConfigured.description = Indicates if this alarm is configured. Deactivating this switch clears the alarm.
+channel-type.somneo.alarmSnooze.label = Alarm Snooze
+channel-type.somneo.alarmSnooze.description = The duration of the snooze function in minutes.
+channel-type.somneo.alarmSound.label = Alarm Clock Sound
+channel-type.somneo.alarmSound.description = The type of sound used for the alarm clock sound.
+channel-type.somneo.alarmSound.state.option.off = No sound
+channel-type.somneo.alarmSound.state.option.wus-1 = Forest Birds
+channel-type.somneo.alarmSound.state.option.wus-2 = Summer Birds
+channel-type.somneo.alarmSound.state.option.wus-3 = Buddha Wakeup
+channel-type.somneo.alarmSound.state.option.wus-4 = Morning Alps
+channel-type.somneo.alarmSound.state.option.wus-5 = Yoga Harmony
+channel-type.somneo.alarmSound.state.option.wus-6 = Nepal Bowls
+channel-type.somneo.alarmSound.state.option.wus-7 = Summer Lake
+channel-type.somneo.alarmSound.state.option.wus-8 = Ocean Waves
+channel-type.somneo.alarmSound.state.option.fmr-1 = FM 1
+channel-type.somneo.alarmSound.state.option.fmr-2 = FM 2
+channel-type.somneo.alarmSound.state.option.fmr-3 = FM 3
+channel-type.somneo.alarmSound.state.option.fmr-4 = FM 4
+channel-type.somneo.alarmSound.state.option.fmr-5 = FM 5
+channel-type.somneo.alarmSwitch.label = Alarm Clock
+channel-type.somneo.alarmSwitch.description = Turn the alarm clock on or off.
+channel-type.somneo.alarmTime.label = Time
+channel-type.somneo.alarmTime.description = Alarm clock time.
+channel-type.somneo.alarmTime.state.pattern = %1$tH:%1$tM
channel-type.somneo.ambientNoise.label = Ambient Noise
channel-type.somneo.ambientNoise.description = Ambient noise played during the sunset.
channel-type.somneo.ambientNoise.state.option.off = No sound
channel-type.somneo.breathingRate.state.option.5 = 8 BR/min
channel-type.somneo.breathingRate.state.option.6 = 9 BR/min
channel-type.somneo.breathingRate.state.option.7 = 10 BR/min
+channel-type.somneo.brightness.label = Light Brightness
+channel-type.somneo.brightness.description = The channel allows to set the light intensity.
channel-type.somneo.colorSchema.label = Color Schema
-channel-type.somneo.colorSchema.description = Choose a personal sunset.
+channel-type.somneo.colorSchema.description = Choose a personal sunrise or sunset.
channel-type.somneo.colorSchema.state.option.0 = Sunny day
channel-type.somneo.colorSchema.state.option.1 = Island red
channel-type.somneo.colorSchema.state.option.2 = Nordic white
channel-type.somneo.light.description = The light switch channel allows to turn the night light on or off.
channel-type.somneo.noise.label = Noise
channel-type.somneo.noise.description = The current noise in dB.
+channel-type.somneo.powerWakeDelay.label = Power Wake Delay
+channel-type.somneo.powerWakeDelay.description = How long after the normal alarm should Power Wake start.
+channel-type.somneo.powerWakeSwitch.label = Power Wake
+channel-type.somneo.powerWakeSwitch.description = Turn the power wake on or off.
channel-type.somneo.preset.label = FM Preset
channel-type.somneo.preset.description = The Device has 5 presets to store radio frequencies.
channel-type.somneo.relaxDuration.label = Duration
channel-type.somneo.relaxDuration.description = The duration of relax breathe program in minutes.
-channel-type.somneo.relaxDuration.state.option.5 = 5 Minutes
-channel-type.somneo.relaxDuration.state.option.10 = 10 Minutes
-channel-type.somneo.relaxDuration.state.option.15 = 15 Minutes
+channel-type.somneo.relaxDuration.state.option.5\ min = 5 Minutes
+channel-type.somneo.relaxDuration.state.option.10\ min = 10 Minutes
+channel-type.somneo.relaxDuration.state.option.15\ min = 15 Minutes
channel-type.somneo.remainingTime.label = Remaining Time
channel-type.somneo.remainingTime.description = Remaining time from an activated program.
+channel-type.somneo.remainingTime.state.pattern = %1$tM:%1$tS min
+channel-type.somneo.repeatDay.label = Days
+channel-type.somneo.repeatDay.description = The days on which the alarm is repeated.
+channel-type.somneo.sunriseBrightness.label = Sunrise Brightness
+channel-type.somneo.sunriseBrightness.description = The channel allows to set the sunrise light intensity.
+channel-type.somneo.sunriseDuration.label = Sunrise Duration
+channel-type.somneo.sunriseDuration.description = The duration of sunrise program in minutes.
+channel-type.somneo.sunriseDuration.state.option.5\ min = 5 Minutes
+channel-type.somneo.sunriseDuration.state.option.10\ min = 10 Minutes
+channel-type.somneo.sunriseDuration.state.option.15\ min = 15 Minutes
+channel-type.somneo.sunriseDuration.state.option.20\ min = 20 Minutes
+channel-type.somneo.sunriseDuration.state.option.25\ min = 25 Minutes
+channel-type.somneo.sunriseDuration.state.option.30\ min = 30 Minutes
+channel-type.somneo.sunriseDuration.state.option.35\ min = 35 Minutes
+channel-type.somneo.sunriseDuration.state.option.40\ min = 40 Minutes
channel-type.somneo.sunsetDuration.label = Duration
channel-type.somneo.sunsetDuration.description = The duration of sunset program in minutes.
-channel-type.somneo.sunsetDuration.state.option.5 = 5 Minutes
-channel-type.somneo.sunsetDuration.state.option.10 = 10 Minutes
-channel-type.somneo.sunsetDuration.state.option.15 = 15 Minutes
-channel-type.somneo.sunsetDuration.state.option.20 = 20 Minutes
-channel-type.somneo.sunsetDuration.state.option.30 = 30 Minutes
-channel-type.somneo.sunsetDuration.state.option.45 = 45 Minutes
-channel-type.somneo.sunsetDuration.state.option.60 = 60 Minutes
+channel-type.somneo.sunsetDuration.state.option.5\ min = 5 Minutes
+channel-type.somneo.sunsetDuration.state.option.10\ min = 10 Minutes
+channel-type.somneo.sunsetDuration.state.option.15\ min = 15 Minutes
+channel-type.somneo.sunsetDuration.state.option.20\ min = 20 Minutes
+channel-type.somneo.sunsetDuration.state.option.30\ min = 30 Minutes
+channel-type.somneo.sunsetDuration.state.option.45\ min = 45 Minutes
+channel-type.somneo.sunsetDuration.state.option.60\ min = 60 Minutes
channel-type.somneo.temperature.label = Temperature
channel-type.somneo.temperature.description = The current temperature in °C.
+
+# channel group types
+
+channel-group-type.somneo.relax.channel.volume.label = Volume
+channel-group-type.somneo.relax.channel.volume.description = Set the volume of the relax breath program.
+channel-group-type.somneo.sunset.channel.volume.label = Volume
+channel-group-type.somneo.sunset.channel.volume.description = Set the volume of the sunset program.
<channel-group id="sunset" typeId="sunset"/>
<channel-group id="relax" typeId="relax"/>
<channel-group id="audio" typeId="audio"/>
+ <channel-group id="alarm" typeId="alarmCommon"/>
+ <channel-group id="alarm1" typeId="alarm">
+ <label>Alarm 1</label>
+ </channel-group>
+ <channel-group id="alarm2" typeId="alarm">
+ <label>Alarm 2</label>
+ </channel-group>
+ <channel-group id="alarm3" typeId="alarmErasable">
+ <label>Alarm 3</label>
+ </channel-group>
+ <channel-group id="alarm4" typeId="alarmErasable">
+ <label>Alarm 4</label>
+ </channel-group>
+ <channel-group id="alarm5" typeId="alarmErasable">
+ <label>Alarm 5</label>
+ </channel-group>
+ <channel-group id="alarm6" typeId="alarmErasable">
+ <label>Alarm 6</label>
+ </channel-group>
+ <channel-group id="alarm7" typeId="alarmErasable">
+ <label>Alarm 7</label>
+ </channel-group>
+ <channel-group id="alarm8" typeId="alarmErasable">
+ <label>Alarm 8</label>
+ </channel-group>
+ <channel-group id="alarm9" typeId="alarmErasable">
+ <label>Alarm 9</label>
+ </channel-group>
+ <channel-group id="alarm10" typeId="alarmErasable">
+ <label>Alarm 10</label>
+ </channel-group>
+ <channel-group id="alarm11" typeId="alarmErasable">
+ <label>Alarm 11</label>
+ </channel-group>
+ <channel-group id="alarm12" typeId="alarmErasable">
+ <label>Alarm 12</label>
+ </channel-group>
+ <channel-group id="alarm13" typeId="alarmErasable">
+ <label>Alarm 13</label>
+ </channel-group>
+ <channel-group id="alarm14" typeId="alarmErasable">
+ <label>Alarm 14</label>
+ </channel-group>
+ <channel-group id="alarm15" typeId="alarmErasable">
+ <label>Alarm 15</label>
+ </channel-group>
+ <channel-group id="alarm16" typeId="alarmErasable">
+ <label>Alarm 16</label>
+ </channel-group>
</channel-groups>
+ <properties>
+ <property name="thingTypeVersion">1</property>
+ <property name="vendor">Philips</property>
+ </properties>
+
<config-description>
<parameter name="hostname" type="text" required="true">
<context>network-address</context>
<default>30</default>
<advanced>true</advanced>
</parameter>
+ <parameter name="refreshIntervalAlarmExtended" type="integer" unit="s" min="1">
+ <label>Refresh Interval for extended alarm clock settings</label>
+ <description>Interval the device is polled in seconds. This polling triggers a sync icon on the device.</description>
+ <default>300</default>
+ <advanced>true</advanced>
+ </parameter>
<parameter name="ignoreSSLErrors" type="boolean">
<label>Ignore SSL Errors</label>
<description>If set to true ignores invalid SSL certificate errors. This is potentially dangerous.</description>
</config-description>
</thing-type>
+ <channel-group-type id="alarm">
+ <label>Alarm Clock</label>
+ <description>Channels to control alarm clock.</description>
+ <category>Alarm</category>
+ <channels>
+ <channel id="switch" typeId="alarmSwitch"/>
+ <channel id="repeatDay" typeId="repeatDay"/>
+ <channel id="alarmTime" typeId="alarmTime"/>
+ <channel id="powerWake" typeId="powerWakeSwitch"/>
+ <channel id="powerWakeDelay" typeId="powerWakeDelay"/>
+ <channel id="sunriseDuration" typeId="sunriseDuration"/>
+ <channel id="sunriseBrightness" typeId="sunriseBrightness"/>
+ <channel id="sunriseSchema" typeId="colorSchema"/>
+ <channel id="sound" typeId="alarmSound"/>
+ <channel id="volume" typeId="system.volume"/>
+ </channels>
+ </channel-group-type>
+
+ <channel-group-type id="alarmCommon">
+ <label>Common Alarm Clock Settings</label>
+ <description>Channels to control alarm clock settings that affect all alarm clocks.</description>
+ <category>Alarm</category>
+ <channels>
+ <channel id="snooze" typeId="alarmSnooze"/>
+ </channels>
+ </channel-group-type>
+
+ <channel-group-type id="alarmErasable">
+ <label>Alarm Clock</label>
+ <description>Channels to control alarm clock.</description>
+ <category>Alarm</category>
+ <channels>
+ <channel id="configured" typeId="alarmConfigured"/>
+ <channel id="switch" typeId="alarmSwitch"/>
+ <channel id="repeatDay" typeId="repeatDay"/>
+ <channel id="alarmTime" typeId="alarmTime"/>
+ <channel id="powerWake" typeId="powerWakeSwitch"/>
+ <channel id="powerWakeDelay" typeId="powerWakeDelay"/>
+ <channel id="sunriseDuration" typeId="sunriseDuration"/>
+ <channel id="sunriseBrightness" typeId="sunriseBrightness"/>
+ <channel id="sunriseSchema" typeId="colorSchema"/>
+ <channel id="sound" typeId="alarmSound"/>
+ <channel id="volume" typeId="system.volume"/>
+ </channels>
+ </channel-group-type>
+
<channel-group-type id="audio">
<label>Audio Player</label>
<description>Channels to control the audio player.</description>
<description>Different light channels.</description>
<category>Light</category>
<channels>
- <channel id="main" typeId="system.brightness"/>
+ <channel id="main" typeId="brightness"/>
<channel id="night" typeId="light"/>
</channels>
</channel-group-type>
<channel id="breathingRate" typeId="breathingRate"/>
<channel id="duration" typeId="relaxDuration"/>
<channel id="guidanceType" typeId="guidanceType"/>
- <channel id="lightIntensity" typeId="system.brightness">
- <label>Light Intensity</label>
- <description>The channel allows to set the light intensity.</description>
- </channel>
+ <channel id="lightIntensity" typeId="sunriseBrightness"/>
<channel id="volume" typeId="system.volume"/>
</channels>
</channel-group-type>
<description>The switch channel allows to turn the sunset program on or off.</description>
</channel>
<channel id="remainingTime" typeId="remainingTime"/>
- <channel id="lightIntensity" typeId="system.brightness">
- <label>Light Intensity</label>
- <description>The channel allows to set the light intensity.</description>
+ <channel id="lightIntensity" typeId="brightness">
+ <label>Sunset Brightness</label>
+ <description>The channel allows to set the sunset light intensity.</description>
</channel>
<channel id="duration" typeId="sunsetDuration"/>
<channel id="colorSchema" typeId="colorSchema"/>
</channels>
</channel-group-type>
+ <channel-type id="alarmConfigured">
+ <item-type>Switch</item-type>
+ <label>Configured</label>
+ <description>Indicates if this alarm is configured. Deactivating this switch clears the alarm.</description>
+ <category>Switch</category>
+ <tags>
+ <tag>Control</tag>
+ </tags>
+ </channel-type>
+
+ <channel-type id="alarmSnooze">
+ <item-type>Number:Time</item-type>
+ <label>Alarm Snooze</label>
+ <description>The duration of the snooze function in minutes.</description>
+ <category>Time</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Duration</tag>
+ </tags>
+ <state pattern="%d min" min="1" max="20" step="1"/>
+ </channel-type>
+
+ <channel-type id="alarmSound">
+ <item-type>String</item-type>
+ <label>Alarm Clock Sound</label>
+ <description>The type of sound used for the alarm clock sound.</description>
+ <category>Noise</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Noise</tag>
+ </tags>
+ <state>
+ <options>
+ <option value="off">No sound</option>
+ <option value="wus-1">Forest Birds</option>
+ <option value="wus-2">Summer Birds</option>
+ <option value="wus-3">Buddha Wakeup</option>
+ <option value="wus-4">Morning Alps</option>
+ <option value="wus-5">Yoga Harmony</option>
+ <option value="wus-6">Nepal Bowls</option>
+ <option value="wus-7">Summer Lake</option>
+ <option value="wus-8">Ocean Waves</option>
+ <option value="fmr-1">FM 1</option>
+ <option value="fmr-2">FM 2</option>
+ <option value="fmr-3">FM 3</option>
+ <option value="fmr-4">FM 4</option>
+ <option value="fmr-5">FM 5</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="alarmSwitch">
+ <item-type>Switch</item-type>
+ <label>Alarm Clock</label>
+ <description>Turn the alarm clock on or off.</description>
+ <category>Switch</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Power</tag>
+ </tags>
+ </channel-type>
+
+ <channel-type id="alarmTime">
+ <item-type>DateTime</item-type>
+ <label>Time</label>
+ <description>Alarm clock time.</description>
+ <category>Time</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Timestamp</tag>
+ </tags>
+ <state pattern="%1$tH:%1$tM"/>
+ </channel-type>
+
<channel-type id="ambientNoise">
<item-type>String</item-type>
<label>Ambient Noise</label>
</state>
</channel-type>
+ <channel-type id="brightness">
+ <item-type>Dimmer</item-type>
+ <label>Light Brightness</label>
+ <description>The channel allows to set the light intensity.</description>
+ <category>Light</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Light</tag>
+ </tags>
+ <state pattern="%d %%" min="0" max="100" step="4"/>
+ </channel-type>
+
<channel-type id="colorSchema">
<item-type>Number</item-type>
<label>Color Schema</label>
- <description>Choose a personal sunset.</description>
+ <description>Choose a personal sunrise or sunset.</description>
<category>Sunset</category>
<tags>
<tag>Control</tag>
<state pattern="%d %unit%" readOnly="true"/>
</channel-type>
+ <channel-type id="powerWakeDelay">
+ <item-type>Number:Time</item-type>
+ <label>Power Wake Delay</label>
+ <description>How long after the normal alarm should Power Wake start.</description>
+ <category>Time</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Duration</tag>
+ </tags>
+ <state pattern="%d min" min="0" max="59" step="1"/>
+ </channel-type>
+
+ <channel-type id="powerWakeSwitch">
+ <item-type>Switch</item-type>
+ <label>Power Wake</label>
+ <description>Turn the power wake on or off.</description>
+ <category>Switch</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Power</tag>
+ </tags>
+ </channel-type>
+
<channel-type id="preset">
<item-type>String</item-type>
<label>FM Preset</label>
</tags>
<state>
<options>
- <option value="5">5 Minutes</option>
- <option value="10">10 Minutes</option>
- <option value="15">15 Minutes</option>
+ <option value="5 min">5 Minutes</option>
+ <option value="10 min">10 Minutes</option>
+ <option value="15 min">15 Minutes</option>
</options>
</state>
</channel-type>
<state pattern="%1$tM:%1$tS min" readOnly="true"/>
</channel-type>
+ <channel-type id="repeatDay">
+ <item-type>Number</item-type>
+ <label>Days</label>
+ <description>The days on which the alarm is repeated.</description>
+ <category>Calendar</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Timestamp</tag>
+ </tags>
+ </channel-type>
+
+ <channel-type id="sunriseBrightness">
+ <item-type>Dimmer</item-type>
+ <label>Sunrise Brightness</label>
+ <description>The channel allows to set the sunrise light intensity.</description>
+ <category>Light</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Light</tag>
+ </tags>
+ <state pattern="%d %%" min="4" max="100" step="4"/>
+ </channel-type>
+
+ <channel-type id="sunriseDuration">
+ <item-type>Number:Time</item-type>
+ <label>Sunrise Duration</label>
+ <description>The duration of sunrise program in minutes.</description>
+ <category>Time</category>
+ <tags>
+ <tag>Control</tag>
+ <tag>Duration</tag>
+ </tags>
+ <state>
+ <options>
+ <option value="5 min">5 Minutes</option>
+ <option value="10 min">10 Minutes</option>
+ <option value="15 min">15 Minutes</option>
+ <option value="20 min">20 Minutes</option>
+ <option value="25 min">25 Minutes</option>
+ <option value="30 min">30 Minutes</option>
+ <option value="35 min">35 Minutes</option>
+ <option value="40 min">40 Minutes</option>
+ </options>
+ </state>
+ </channel-type>
+
<channel-type id="sunsetDuration">
<item-type>Number:Time</item-type>
<label>Duration</label>
</tags>
<state>
<options>
- <option value="5">5 Minutes</option>
- <option value="10">10 Minutes</option>
- <option value="15">15 Minutes</option>
- <option value="20">20 Minutes</option>
- <option value="30">30 Minutes</option>
- <option value="45">45 Minutes</option>
- <option value="60">60 Minutes</option>
+ <option value="5 min">5 Minutes</option>
+ <option value="10 min">10 Minutes</option>
+ <option value="15 min">15 Minutes</option>
+ <option value="20 min">20 Minutes</option>
+ <option value="30 min">30 Minutes</option>
+ <option value="45 min">45 Minutes</option>
+ <option value="60 min">60 Minutes</option>
</options>
</state>
</channel-type>
--- /dev/null
+<?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>