/bundles/org.openhab.binding.siemensrds/ @andrewfg
/bundles/org.openhab.binding.silvercrestwifisocket/ @jmvaz
/bundles/org.openhab.binding.sinope/ @chaton78
-/bundles/org.openhab.binding.sleepiq/ @syphr42
+/bundles/org.openhab.binding.sleepiq/ @syphr42 @mhilbush
/bundles/org.openhab.binding.smaenergymeter/ @monnimeter
/bundles/org.openhab.binding.smartmeter/ @msteigenberger
/bundles/org.openhab.binding.smartthings/ @BobRak
The bridge requires a username and a password.
Optionally, you can also specify a polling interval.
-To enable verbose logging of HTTP requests and responses regarding the cloud service, enable DEBUG level logging on ```SleepIQCloudHandler```.
-
| Configuration Parameter | Type | Description | Default |
|-------------------------|---------|--------------------------------------------------------|---------|
| username | text | Username of a registered SleepIQ account owner | |
| password | text | Password of a registered SleepIQ account owner | |
-| pollingInterval | integer | Seconds between fetching values from the cloud service | 60 |
+| pollingInterval | integer | Seconds between fetching values from the cloud service | 120 |
### Dual-Chamber Bed (Thing ID: "dualBed")
### Sample Thing Configuration
```java
-Bridge sleepiq:cloud:1 [ username="mail@example.com", password="password", pollingInterval=60, logging=false ]
+Bridge sleepiq:cloud:1 [ username="mail@example.com", password="password", pollingInterval=120 ]
{
Thing dualBed master [ bedId="-9999999999999999999" ]
Thing dualBed guest [ bedId="-8888888888888888888" ]
### Chamber Channel Group
-All channels within this group are read-only.
-
-| Channel ID | Item Type | Description |
-|----------------------|-----------|---------------------------------------------------------------------------------------------------------------------|
-| inBed | Switch | The presence of a person or object on the chamber |
-| sleepNumber | Number | The Sleep Number setting of the chamber |
-| pressure | Number | The current pressure inside the chamber |
-| lastLink | String | The amount of time that has passed since a connection was made from the chamber to the cloud service (D d HH:MM:SS) |
-| alertId | Number | Identifier for an alert condition with the chamber |
-| alertDetailedMessage | String | A detailed message describing an alert condition with the chamber |
+All channels within this group are read-only, except for the sleepNumber and privacyMode channels.
+
+| Channel ID | Item Type | Description |
+|-----------------------------------|----------------|---------------------------------------------------------------------------------------------------------------------|
+| inBed | Switch | The presence of a person or object on the chamber |
+| sleepNumber | Number | The Sleep Number setting of the chamber. Set the sleep number of the chamber by sending a command to the sleepNumber channel with a value between 5 and 100. The value must be a multiple of 5 |
+
+| sleepGoalMinutes | Number:Time | The person's sleep goal in minutes |
+| pressure | Number | The current pressure inside the chamber |
+| privacyMode | Switch | Enable or disable privacy mode |
+| lastLink | String | The amount of time that has passed since a connection was made from the chamber to the cloud service (D d HH:MM:SS) |
+| alertId | Number | Identifier for an alert condition with the chamber |
+| alertDetailedMessage | String | A detailed message describing an alert condition with the chamber |
+| todaySleepIQ | Number | The Sleep IQ score for the current day |
+| todayAverageHeartRate | Number | The average heart rate for the current day |
+| todayAverageRespirationRate | Number | The average respiration rate for the current day |
+| todayMessage | String | A description of the sleep quality for the current day |
+| todaySleepDurationSeconds | Number:Time | The duration of sleep for the current day |
+| monthlySleepIQ | Number | The average Sleep IQ score for the current month |
+| monthlyAverageHeartRate | Number | The average heart rate for the current month |
+| monthlyAverageRespirationRate | Number | The average respiration rate for the current month |
## Items
Here is a sample item configuration:
```java
-Switch MasterBedroom_SleepIQ_InBed_Alice "In Bed [%s]" { channel="sleepiq:dualBed:1:master:left#inBed" }
-Number MasterBedroom_SleepIQ_SleepNumber_Alice "Sleep Number [%s]" { channel="sleepiq:dualBed:1:master:left#sleepNumber" }
-Number MasterBedroom_SleepIQ_Pressure_Alice "Pressure [%s]" { channel="sleepiq:dualBed:1:master:left#pressure" }
-String MasterBedroom_SleepIQ_LastLink_Alice "Last Update [%s]" { channel="sleepiq:dualBed:1:master:left#lastLink" }
-Number MasterBedroom_SleepIQ_AlertId_Alice "Alert ID [%s]" { channel="sleepiq:dualBed:1:master:left#alertId" }
-String MasterBedroom_SleepIQ_AlertMessage_Alice "Alert Message [%s]" { channel="sleepiq:dualBed:1:master:left#alertDetailedMessage" }
-
-Switch MasterBedroom_SleepIQ_InBed_Bob "In Bed [%s]" { channel="sleepiq:dualBed:1:master:right#inBed" }
-Number MasterBedroom_SleepIQ_SleepNumber_Bob "Sleep Number [%s]" { channel="sleepiq:dualBed:1:master:right#sleepNumber" }
-Number MasterBedroom_SleepIQ_Pressure_Bob "Pressure [%s]" { channel="sleepiq:dualBed:1:master:right#pressure" }
-String MasterBedroom_SleepIQ_LastLink_Bob "Last Update [%s]" { channel="sleepiq:dualBed:1:master:right#lastLink" }
-Number MasterBedroom_SleepIQ_AlertId_Bob "Alert ID [%s]" { channel="sleepiq:dualBed:1:master:right#alertId" }
-String MasterBedroom_SleepIQ_AlertMessage_Bob "Alert Message [%s]" { channel="sleepiq:dualBed:1:master:right#alertDetailedMessage" }
+Switch MasterBR_SleepIQ_InBed_Alice "In Bed [%s]" { channel="sleepiq:dualBed:1:master:left#inBed" }
+Number MasterBR_SleepIQ_SleepNumber_Alice "Sleep Number [%s]" { channel="sleepiq:dualBed:1:master:left#sleepNumber" }
+Number:Time MasterBR_SleepIQ_SleepGoal_Alice "Sleep Goal [%d min]" { channel="sleepiq:dualBed:1:master:left#sleepGoalMinutes"
+Number MasterBR_SleepIQ_Pressure_Alice "Pressure [%s]" { channel="sleepiq:dualBed:1:master:left#pressure" }
+Switch MasterBR_SleepIQ_PrivacyMode_Alice "Privacy Mode [%s]" { channel="sleepiq:dualBed:1:master:left#privacyMode" }
+String MasterBR_SleepIQ_LastLink_Alice "Last Update [%s]" { channel="sleepiq:dualBed:1:master:left#lastLink" }
+Number MasterBR_SleepIQ_AlertId_Alice "Alert ID [%s]" { channel="sleepiq:dualBed:1:master:left#alertId" }
+String MasterBR_SleepIQ_AlertMessage_Alice "Alert Message [%s]" { channel="sleepiq:dualBed:1:master:left#alertDetailedMessage" }
+Number MasterBR_SleepIQ_DailySleepIQ_Alice "Daily Sleep IQ [%.0f]" { channel="sleepiq:dualBed:1:master:left#todaySleepIQ" }
+Number MasterBR_SleepIQ_DailyHeartRate_Alice "Daily Heart Rate [%.0f]" { channel="sleepiq:dualBed:1:master:left#todayAverageHeartRate" }
+Number MasterBR_SleepIQ_DailyRespRate_Alice "Daily Respiration Rate [%.0f]" { channel="sleepiq:dualBed:1:master:left#todayAverageRespirationRate"}
+String MasterBR_SleepIQ_DailyMessage_Alice "Daily Message [%s]" { channel="sleepiq:dualBed:1:master:left#todayMessage"}
+Number MasterBR_SleepIQ_DailyDuration_Alice "Daily Sleep Duration [%.0f]" { channel="sleepiq:dualBed:1:master:left#todaySleepDurationSeconds"}
+Number:Time MasterBR_SleepIQ_MonthlySleepIQ_Alice "Monthly Sleep IQ [%d s]" { channel="sleepiq:dualBed:1:master:left#monthlySleepIQ"}
+Number MasterBR_SleepIQ_MonthlyHeartRate_Alice "Monthly Heart Rate [%.0f]" { channel="sleepiq:dualBed:1:master:left#monthlyAverageHeartRate"}
+Number MasterBR_SleepIQ_MonthlyRespRate_Alice "Monthly Respiration Rate [%.0f]" { channel="sleepiq:dualBed:1:master:left#monthlyAverageRespirationRate"}
+
+
+Switch MasterBR_SleepIQ_InBed_Bob "In Bed [%s]" { channel="sleepiq:dualBed:1:master:right#inBed" }
+Number MasterBR_SleepIQ_SleepNumber_Bob "Sleep Number [%s]" { channel="sleepiq:dualBed:1:master:right#sleepNumber" }
+Number MasterBR_SleepIQ_SleepGoal_Alice "Sleep Goal [%d min]" { channel="sleepiq:dualBed:1:master:left#sleepGoalMinutes"
+Number:Time MasterBR_SleepIQ_Pressure_Bob "Pressure [%s]" { channel="sleepiq:dualBed:1:master:right#pressure" }
+Switch MasterBR_SleepIQ_PrivacyMode_Bob "Privacy Mode [%s]" { channel="sleepiq:dualBed:1:master:right#privacyMode" }
+String MasterBR_SleepIQ_LastLink_Bob "Last Update [%s]" { channel="sleepiq:dualBed:1:master:right#lastLink" }
+Number MasterBR_SleepIQ_AlertId_Bob "Alert ID [%s]" { channel="sleepiq:dualBed:1:master:right#alertId" }
+String MasterBR_SleepIQ_AlertMessage_Bob "Alert Message [%s]" { channel="sleepiq:dualBed:1:master:right#alertDetailedMessage" }
+Number MasterBR_SleepIQ_DailySleepIQ_Bob "Daily Sleep IQ [%.0f]" { channel="sleepiq:dualBed:1:master:right#todaySleepIQ" }
+Number MasterBR_SleepIQ_DailyHeartRate_Bob "Daily Heart Rate [%.0f]" { channel="sleepiq:dualBed:1:master:right#todayAverageHeartRate" }
+Number MasterBR_SleepIQ_DailyRespRate_Bob "Daily Respiration Rate [%.0f]" { channel="sleepiq:dualBed:1:master:right#todayAverageRespirationRate"}
+String MasterBR_SleepIQ_DailyMessage_Bob "Daily Message [%s]" { channel="sleepiq:dualBed:1:master:right#todayMessage"}
+Number:Time MasterBR_SleepIQ_DailyDuration_Bob "Daily Sleep Duration [%d s]" { channel="sleepiq:dualBed:1:master:right#todaySleepDurationSeconds"}
+Number MasterBR_SleepIQ_MonthlySleepIQ_Bob "Monthly Sleep IQ [%.0f]" { channel="sleepiq:dualBed:1:master:right#monthlySleepIQ"}
+Number MasterBR_SleepIQ_MonthlyHeartRate_Bob "Monthly Heart Rate [%.0f]" { channel="sleepiq:dualBed:1:master:right#monthlyAverageHeartRate"}
+Number MasterBR_SleepIQ_MonthlyRespRate_Bob "Monthly Respiration Rate [%.0f]" { channel="sleepiq:dualBed:1:master:right#monthlyAverageRespirationRate"}
```
<name>openHAB Add-ons :: Bundles :: SleepIQ Binding</name>
- <properties>
- <dep.noembedding>provider-gson</dep.noembedding>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.12</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>build-helper-maven-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>add-source</goal>
- </goals>
- <phase>generate-sources</phase>
- <configuration>
- <sources>
- <source>src/3rdparty/java</source>
- </sources>
- </configuration>
- </execution>
- <execution>
- <id>add-test-source</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>add-test-source</goal>
- </goals>
- <configuration>
- <sources>
- <source>src/3rdparty/test</source>
- </sources>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
</project>
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api;
-
-import org.openhab.binding.sleepiq.api.model.Failure;
-
-public class BedNotFoundException extends SleepIQException
-{
- private static final long serialVersionUID = 1L;
-
- public BedNotFoundException(Failure failure)
- {
- super(failure);
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api;
-
-import java.net.URI;
-import java.util.logging.Level;
-
-/**
- * This class represents configuration parameters for using {@link SleepIQ}.
- *
- * @author Gregory Moyer
- */
-public class Configuration
-{
- private String username;
- private String password;
-
- private URI baseUri = URI.create("https://api.sleepiq.sleepnumber.com/rest");
-
- private boolean logging = false;
-
- /**
- * Get the username on the account.
- *
- * @return the username
- */
- public String getUsername()
- {
- return username;
- }
-
- /**
- * Set the username on the account. This should be the username used to
- * register with SleepIQ.
- *
- * @param username
- * the value to set
- */
- public void setUsername(String username)
- {
- this.username = username;
- }
-
- /**
- * Set the username on the account. This should be the username used to
- * register with SleepIQ.
- *
- * @param username
- * the value to set
- * @return this configuration instance
- */
- public Configuration withUsername(String username)
- {
- setUsername(username);
- return this;
- }
-
- /**
- * Get the password on the account.
- *
- * @return the password
- */
- public String getPassword()
- {
- return password;
- }
-
- /**
- * Set the password on the account. This should be the password used to
- * register with SleepIQ.
- *
- * @param password
- * the value to set
- */
- public void setPassword(String password)
- {
- this.password = password;
- }
-
- /**
- * Set the password on the account. This should be the password used to
- * register with SleepIQ.
- *
- * @param password
- * the value to set
- * @return this configuration instance
- */
- public Configuration withPassword(String password)
- {
- setPassword(password);
- return this;
- }
-
- /**
- * Get the base URI of the SleepIQ cloud service.
- *
- * @return the base URI
- */
- public URI getBaseUri()
- {
- return baseUri;
- }
-
- /**
- * Set the base URI of the SleepIQ cloud service. It is unlikely that this
- * will need to be changed from its default value.
- *
- * @param baseUri
- * the value to set
- */
- public void setBaseUri(URI baseUri)
- {
- this.baseUri = baseUri;
- }
-
- /**
- * Set the base URI of the SleepIQ cloud service. It is unlikely that this
- * will need to be changed from its default value.
- *
- * @param baseUri
- * the value to set
- * @return this configuration instance
- */
- public Configuration withBaseUri(URI baseUri)
- {
- setBaseUri(baseUri);
- return this;
- }
-
- /**
- * Get the logging flag.
- *
- * @return the logging flag
- */
- public boolean isLogging()
- {
- return logging;
- }
-
- /**
- * Set the logging flag. When this is set to <code>true</code>, all requests
- * and responses will be logged at the {@link Level#INFO} level. <b>This
- * includes usernames and passwords!</b>
- *
- * @param logging
- * the value to set
- */
- public void setLogging(boolean logging)
- {
- this.logging = logging;
- }
-
- /**
- * Set the logging flag. When this is set to <code>true</code>, all requests
- * and responses will be logged at the {@link Level#INFO} level. <b>This
- * includes usernames and passwords!</b>
- *
- * @param logging
- * the value to set
- * @return this configuration instance
- */
- public Configuration withLogging(boolean logging)
- {
- setLogging(logging);
- return this;
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api;
-
-import org.openhab.binding.sleepiq.api.model.Failure;
-
-public class LoginException extends SleepIQException
-{
- private static final long serialVersionUID = 1L;
-
- public LoginException(Failure failure)
- {
- super(failure);
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api;
-
-import java.util.List;
-
-import javax.ws.rs.client.ClientBuilder;
-
-import org.openhab.binding.sleepiq.api.impl.SleepIQImpl;
-import org.openhab.binding.sleepiq.api.model.Bed;
-import org.openhab.binding.sleepiq.api.model.FamilyStatus;
-import org.openhab.binding.sleepiq.api.model.LoginInfo;
-import org.openhab.binding.sleepiq.api.model.PauseMode;
-import org.openhab.binding.sleepiq.api.model.Sleeper;
-
-/**
- * This interface is the main API to access the SleepIQ system.
- *
- * @author Gregory Moyer
- */
-public interface SleepIQ {
- /**
- * Login to the {@link Configuration configured} account. This method is not
- * required to be called before other methods because all methods must
- * ensure login before acting. However, when the only desired action is to
- * login and not retrieve other data, this method is the most efficient
- * option.
- *
- * @return basic information about the logged in user
- * @throws UnauthorizedException
- * if the credentials provided are not valid
- * @throws LoginException
- * if the login request fails for any reason other than bad
- * credentials (including missing credentials)
- */
- public LoginInfo login() throws LoginException;
-
- /**
- * Get a list of beds connected to the account.
- *
- * @return the list of beds
- */
- public List<Bed> getBeds();
-
- /**
- * Get a list of people registered to this account for beds or bed positions
- * (left or right side).
- *
- * @return the list of sleepers
- */
- public List<Sleeper> getSleepers();
-
- /**
- * Get the status of all beds and all air chambers registered to this
- * account.
- *
- * @return the complete status of beds on the account
- */
- public FamilyStatus getFamilyStatus();
-
- /**
- * Get the status of "pause mode" (disabling SleepIQ data upload) for a
- * specific bed. A bed in pause mode will send no information to the SleepIQ
- * cloud services. For example, if a sleeper is in bed and disables SleepIQ
- * (enables pause mode), the service will continue to report that the bed is
- * occupied even after the sleeper exits the bed until pause mode is
- * disabled.
- *
- * @param bedId
- * the unique identifier of the bed to query
- * @return the status of pause mode for the specified bed
- * @throws BedNotFoundException
- * if the bed identifier was not found on the account
- */
- public PauseMode getPauseMode(String bedId) throws BedNotFoundException;
-
- /**
- * Create a default implementation instance of this interface. Each call to
- * this method will create a new object.
- *
- * @param config
- * the configuration to use for the new instance
- * @return a concrete implementation of this interface
- */
- public static SleepIQ create(Configuration config, ClientBuilder clientBuilder) {
- return new SleepIQImpl(config, clientBuilder);
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api;
-
-import org.openhab.binding.sleepiq.api.model.Failure;
-
-public class SleepIQException extends Exception
-{
- private static final long serialVersionUID = 1L;
-
- private final Failure failure;
-
- public SleepIQException(Failure failure)
- {
- super(failure.getError().getMessage());
- this.failure = failure;
- }
-
- public Failure getFailure()
- {
- return failure;
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api;
-
-import org.openhab.binding.sleepiq.api.model.Failure;
-
-public class UnauthorizedException extends LoginException
-{
- private static final long serialVersionUID = 1L;
-
- public UnauthorizedException(Failure failure)
- {
- super(failure);
- }
-}
+++ /dev/null
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright (c) 2011-2015 Oracle and/or its affiliates. All rights reserved.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common Development
- * and Distribution License("CDDL") (collectively, the "License"). You
- * may not use this file except in compliance with the License. You can
- * obtain a copy of the License at
- * http://glassfish.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt. See the License for the specific
- * language governing permissions and limitations under the License.
- *
- * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
- *
- * GPL Classpath Exception:
- * Oracle designates this particular file as subject to the "Classpath"
- * exception as provided by Oracle in the GPL Version 2 section of the License
- * file that accompanied this code.
- *
- * Modifications:
- * If applicable, add the following below the License Header, with the fields
- * enclosed by brackets [] replaced by your own identifying information:
- * "Portions Copyright [year] [name of copyright owner]"
- *
- * Contributor(s):
- * If you wish your version of this file to be governed by only the CDDL or
- * only the GPL Version 2, indicate your decision by adding "[Contributor]
- * elects to include this software in this distribution under the [CDDL or GPL
- * Version 2] license." If you don't indicate a single choice of license, a
- * recipient has the option to distribute your version of this file under
- * either the CDDL, the GPL Version 2 or to extend the choice of license to
- * its licensees as provided above. However, if you add GPL Version 2 code
- * and therefore, elected the GPL Version 2 license, then the option applies
- * only if the new code is made subject to such option by the copyright
- * holder.
- */
-package org.openhab.binding.sleepiq.api.filter;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.nio.charset.Charset;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Logger;
-
-import javax.annotation.Priority;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.client.ClientRequestContext;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.ClientResponseContext;
-import javax.ws.rs.client.ClientResponseFilter;
-import javax.ws.rs.container.ContainerRequestContext;
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.container.ContainerResponseContext;
-import javax.ws.rs.container.ContainerResponseFilter;
-import javax.ws.rs.container.PreMatching;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.WriterInterceptor;
-import javax.ws.rs.ext.WriterInterceptorContext;
-
-/**
- * Universal logging filter.
- * <p/>
- * Can be used on client or server side. Has the highest priority.
- *
- * @author Pavel Bucek (pavel.bucek at oracle.com)
- * @author Martin Matula
- */
-@PreMatching
-@Priority(Integer.MIN_VALUE)
-public final class LoggingFilter implements ContainerRequestFilter, ClientRequestFilter, ContainerResponseFilter,
- ClientResponseFilter, WriterInterceptor {
-
- public static final Charset UTF8 = Charset.forName("UTF-8");
-
- private static final Logger LOGGER = Logger.getLogger(LoggingFilter.class.getName());
- private static final String NOTIFICATION_PREFIX = "* ";
- private static final String REQUEST_PREFIX = "> ";
- private static final String RESPONSE_PREFIX = "< ";
- private static final String ENTITY_LOGGER_PROPERTY = LoggingFilter.class.getName() + ".entityLogger";
- private static final String LOGGING_ID_PROPERTY = LoggingFilter.class.getName() + ".id";
-
- private static final Comparator<Map.Entry<String, List<String>>> COMPARATOR = new Comparator<Map.Entry<String, List<String>>>() {
-
- @Override
- public int compare(final Map.Entry<String, List<String>> o1, final Map.Entry<String, List<String>> o2) {
- return o1.getKey().compareToIgnoreCase(o2.getKey());
- }
- };
-
- private static final int DEFAULT_MAX_ENTITY_SIZE = 8 * 1024;
-
- //
- private final Logger logger;
- private final AtomicLong _id = new AtomicLong(0);
- private final boolean printEntity;
- private final int maxEntitySize;
-
- /**
- * Create a logging filter logging the request and response to a default JDK
- * logger, named as the fully qualified class name of this class. Entity
- * logging is turned off by default.
- */
- public LoggingFilter() {
- this(LOGGER, false);
- }
-
- /**
- * Create a logging filter with custom logger and custom settings of entity
- * logging.
- *
- * @param logger the logger to log requests and responses.
- * @param printEntity if true, entity will be logged as well up to the default maxEntitySize, which is 8KB
- */
- public LoggingFilter(final Logger logger, final boolean printEntity) {
- this.logger = logger;
- this.printEntity = printEntity;
- this.maxEntitySize = DEFAULT_MAX_ENTITY_SIZE;
- }
-
- /**
- * Creates a logging filter with custom logger and entity logging turned on, but potentially limiting the size
- * of entity to be buffered and logged.
- *
- * @param logger the logger to log requests and responses.
- * @param maxEntitySize maximum number of entity bytes to be logged (and buffered) - if the entity is larger,
- * logging filter will print (and buffer in memory) only the specified number of bytes
- * and print "...more..." string at the end. Negative values are interpreted as zero.
- */
- public LoggingFilter(final Logger logger, final int maxEntitySize) {
- this.logger = logger;
- this.printEntity = true;
- this.maxEntitySize = Math.max(0, maxEntitySize);
- }
-
- private void log(final StringBuilder b) {
- if (logger != null) {
- logger.info(b.toString());
- }
- }
-
- private StringBuilder prefixId(final StringBuilder b, final long id) {
- b.append(Long.toString(id)).append(" ");
- return b;
- }
-
- private void printRequestLine(final StringBuilder b, final String note, final long id, final String method,
- final URI uri) {
- prefixId(b, id).append(NOTIFICATION_PREFIX).append(note).append(" on thread ")
- .append(Thread.currentThread().getName()).append("\n");
- prefixId(b, id).append(REQUEST_PREFIX).append(method).append(" ").append(uri.toASCIIString()).append("\n");
- }
-
- private void printResponseLine(final StringBuilder b, final String note, final long id, final int status) {
- prefixId(b, id).append(NOTIFICATION_PREFIX).append(note).append(" on thread ")
- .append(Thread.currentThread().getName()).append("\n");
- prefixId(b, id).append(RESPONSE_PREFIX).append(Integer.toString(status)).append("\n");
- }
-
- private void printPrefixedHeaders(final StringBuilder b, final long id, final String prefix,
- final MultivaluedMap<String, String> headers) {
- for (final Map.Entry<String, List<String>> headerEntry : getSortedHeaders(headers.entrySet())) {
- final List<?> val = headerEntry.getValue();
- final String header = headerEntry.getKey();
-
- if (val.size() == 1) {
- prefixId(b, id).append(prefix).append(header).append(": ").append(val.get(0)).append("\n");
- } else {
- final StringBuilder sb = new StringBuilder();
- boolean add = false;
- for (final Object s : val) {
- if (add) {
- sb.append(',');
- }
- add = true;
- sb.append(s);
- }
- prefixId(b, id).append(prefix).append(header).append(": ").append(sb.toString()).append("\n");
- }
- }
- }
-
- private Set<Map.Entry<String, List<String>>> getSortedHeaders(final Set<Map.Entry<String, List<String>>> headers) {
- final TreeSet<Map.Entry<String, List<String>>> sortedHeaders = new TreeSet<Map.Entry<String, List<String>>>(
- COMPARATOR);
- sortedHeaders.addAll(headers);
- return sortedHeaders;
- }
-
- private InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset)
- throws IOException {
- if (!stream.markSupported()) {
- stream = new BufferedInputStream(stream);
- }
- stream.mark(maxEntitySize + 1);
- final byte[] entity = new byte[maxEntitySize + 1];
- final int entitySize = stream.read(entity);
- b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset));
- if (entitySize > maxEntitySize) {
- b.append("...more...");
- }
- b.append('\n');
- stream.reset();
- return stream;
- }
-
- @Override
- public void filter(final ClientRequestContext context) throws IOException {
- final long id = _id.incrementAndGet();
- context.setProperty(LOGGING_ID_PROPERTY, id);
-
- final StringBuilder b = new StringBuilder();
-
- printRequestLine(b, "Sending client request", id, context.getMethod(), context.getUri());
- printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getStringHeaders());
-
- if (printEntity && context.hasEntity()) {
- final OutputStream stream = new LoggingStream(b, context.getEntityStream());
- context.setEntityStream(stream);
- context.setProperty(ENTITY_LOGGER_PROPERTY, stream);
- // not calling log(b) here - it will be called by the interceptor
- } else {
- log(b);
- }
- }
-
- @Override
- public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext)
- throws IOException {
- final Object requestId = requestContext.getProperty(LOGGING_ID_PROPERTY);
- final long id = requestId != null ? (Long) requestId : _id.incrementAndGet();
-
- final StringBuilder b = new StringBuilder();
-
- printResponseLine(b, "Client response received", id, responseContext.getStatus());
- printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getHeaders());
-
- if (printEntity && responseContext.hasEntity()) {
- responseContext.setEntityStream(
- logInboundEntity(b, responseContext.getEntityStream(), getCharset(responseContext.getMediaType())));
- }
-
- log(b);
- }
-
- @Override
- public void filter(final ContainerRequestContext context) throws IOException {
- final long id = _id.incrementAndGet();
- context.setProperty(LOGGING_ID_PROPERTY, id);
-
- final StringBuilder b = new StringBuilder();
-
- printRequestLine(b, "Server has received a request", id, context.getMethod(),
- context.getUriInfo().getRequestUri());
- printPrefixedHeaders(b, id, REQUEST_PREFIX, context.getHeaders());
-
- if (printEntity && context.hasEntity()) {
- context.setEntityStream(logInboundEntity(b, context.getEntityStream(), getCharset(context.getMediaType())));
- }
-
- log(b);
- }
-
- @Override
- public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext)
- throws IOException {
- final Object requestId = requestContext.getProperty(LOGGING_ID_PROPERTY);
- final long id = requestId != null ? (Long) requestId : _id.incrementAndGet();
-
- final StringBuilder b = new StringBuilder();
-
- printResponseLine(b, "Server responded with a response", id, responseContext.getStatus());
- printPrefixedHeaders(b, id, RESPONSE_PREFIX, responseContext.getStringHeaders());
-
- if (printEntity && responseContext.hasEntity()) {
- final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream());
- responseContext.setEntityStream(stream);
- requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream);
- // not calling log(b) here - it will be called by the interceptor
- } else {
- log(b);
- }
- }
-
- @Override
- public void aroundWriteTo(final WriterInterceptorContext writerInterceptorContext)
- throws IOException, WebApplicationException {
- final LoggingStream stream = (LoggingStream) writerInterceptorContext.getProperty(ENTITY_LOGGER_PROPERTY);
- writerInterceptorContext.proceed();
- if (stream != null) {
- log(stream.getStringBuilder(getCharset(writerInterceptorContext.getMediaType())));
- }
- }
-
- private class LoggingStream extends FilterOutputStream {
-
- private final StringBuilder b;
- private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- LoggingStream(final StringBuilder b, final OutputStream inner) {
- super(inner);
-
- this.b = b;
- }
-
- StringBuilder getStringBuilder(final Charset charset) {
- // write entity to the builder
- final byte[] entity = baos.toByteArray();
-
- b.append(new String(entity, 0, Math.min(entity.length, maxEntitySize), charset));
- if (entity.length > maxEntitySize) {
- b.append("...more...");
- }
- b.append('\n');
-
- return b;
- }
-
- @Override
- public void write(final int i) throws IOException {
- if (baos.size() <= maxEntitySize) {
- baos.write(i);
- }
- out.write(i);
- }
- }
-
- /**
- * Get the character set from a media type.
- * <p>
- * The character set is obtained from the media type parameter "charset".
- * If the parameter is not present the {@link #UTF8} charset is utilized.
- *
- * @param m the media type.
- * @return the character set.
- */
- public static Charset getCharset(MediaType m) {
- String name = (m == null) ? null : m.getParameters().get(MediaType.CHARSET_PARAMETER);
- return (name == null) ? UTF8 : Charset.forName(name);
- }
-
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.impl;
-
-import javax.ws.rs.client.Client;
-
-import com.google.gson.Gson;
-
-public abstract class AbstractClient
-{
- private volatile Client client;
- private volatile Gson gson;
-
- protected Client getClient()
- {
- if (client == null)
- {
- synchronized (this)
- {
- if (client == null)
- {
- client = createClient();
- }
- }
- }
-
- return client;
- }
-
- protected Gson getGson()
- {
- if (gson == null)
- {
- synchronized (this)
- {
- if (gson == null)
- {
- gson = createGson();
- }
- }
- }
-
- return gson;
- }
-
- protected abstract Client createClient();
-
- protected Gson createGson()
- {
- return GsonGenerator.create();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.impl;
-
-public class Endpoints
-{
- private static final String LOGIN = "login";
- private static final String BED = "bed";
- private static final String SLEEPER = "sleeper";
- private static final String FAMILY_STATUS = "familyStatus";
- private static final String PAUSE_MODE = "pauseMode";
-
- public static String login()
- {
- return LOGIN;
- }
-
- public static String bed()
- {
- return BED;
- }
-
- public static String sleeper()
- {
- return SLEEPER;
- }
-
- public static String familyStatus()
- {
- return FAMILY_STATUS;
- }
-
- public static String pauseMode()
- {
- return PAUSE_MODE;
- }
-
- // @formatter:off
- private Endpoints() {}
- // @formatter:on
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.impl;
-
-import org.openhab.binding.sleepiq.api.impl.typeadapters.JSR310TypeAdapters;
-import org.openhab.binding.sleepiq.api.impl.typeadapters.TimeSinceTypeAdapter;
-import org.openhab.binding.sleepiq.api.model.TimeSince;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-
-public class GsonGenerator
-{
- public static Gson create()
- {
- return create(false);
- }
-
- public static Gson create(boolean prettyPrint)
- {
- GsonBuilder builder = new GsonBuilder();
-
- // add Java 8 Time API support
- JSR310TypeAdapters.registerJSR310TypeAdapters(builder);
-
- builder.registerTypeAdapter(TimeSince.class, new TimeSinceTypeAdapter());
-
- if (prettyPrint)
- {
- builder.setPrettyPrinting();
- }
-
- return builder.create();
- }
-
- // @formatter:off
- private GsonGenerator() {}
- // @formatter:on
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.impl;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.ClientRequestContext;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-
-import org.openhab.binding.sleepiq.api.BedNotFoundException;
-import org.openhab.binding.sleepiq.api.Configuration;
-import org.openhab.binding.sleepiq.api.LoginException;
-import org.openhab.binding.sleepiq.api.SleepIQ;
-import org.openhab.binding.sleepiq.api.UnauthorizedException;
-import org.openhab.binding.sleepiq.api.filter.LoggingFilter;
-import org.openhab.binding.sleepiq.api.model.Bed;
-import org.openhab.binding.sleepiq.api.model.BedsResponse;
-import org.openhab.binding.sleepiq.api.model.Failure;
-import org.openhab.binding.sleepiq.api.model.FamilyStatus;
-import org.openhab.binding.sleepiq.api.model.LoginInfo;
-import org.openhab.binding.sleepiq.api.model.LoginRequest;
-import org.openhab.binding.sleepiq.api.model.PauseMode;
-import org.openhab.binding.sleepiq.api.model.Sleeper;
-import org.openhab.binding.sleepiq.api.model.SleepersResponse;
-import org.openhab.binding.sleepiq.internal.GsonProvider;
-
-public class SleepIQImpl extends AbstractClient implements SleepIQ {
- protected static final String PARAM_KEY = "_k";
-
- protected static final String DATA_BED_ID = "bedId";
-
- protected final Configuration config;
-
- private volatile LoginInfo loginInfo;
-
- private final ClientBuilder clientBuilder;
-
- public SleepIQImpl(Configuration config, ClientBuilder clientBuilder) {
- this.config = config;
- this.clientBuilder = clientBuilder;
- }
-
- @Override
- public LoginInfo login() throws LoginException {
- if (loginInfo == null) {
- synchronized (this) {
- if (loginInfo == null) {
- Response response = getClient().target(config.getBaseUri()).path(Endpoints.login())
- .request(MediaType.APPLICATION_JSON_TYPE).put(Entity.json(new LoginRequest()
- .withLogin(config.getUsername()).withPassword(config.getPassword())));
-
- if (isUnauthorized(response)) {
- throw new UnauthorizedException(response.readEntity(Failure.class));
- }
-
- if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) {
- throw new LoginException(response.readEntity(Failure.class));
- }
-
- // add the received cookies to all future requests
- getClient().register(new ClientRequestFilter() {
- @Override
- public void filter(ClientRequestContext requestContext) throws IOException {
- List<Object> cookies = response.getCookies().values().stream()
- .map(newCookie -> newCookie.toCookie()).collect(Collectors.toList());
- requestContext.getHeaders().put("Cookie", cookies);
- }
- });
-
- loginInfo = response.readEntity(LoginInfo.class);
- }
- }
- }
-
- return loginInfo;
- }
-
- @Override
- public List<Bed> getBeds() {
- return getSessionResponse(this::getBedsResponse).readEntity(BedsResponse.class).getBeds();
- }
-
- protected Response getBedsResponse(Map<String, Object> data) throws LoginException {
- LoginInfo login = login();
- return getClient().target(config.getBaseUri()).path(Endpoints.bed()).queryParam(PARAM_KEY, login.getKey())
- .request(MediaType.APPLICATION_JSON_TYPE).get();
- }
-
- @Override
- public List<Sleeper> getSleepers() {
- return getSessionResponse(this::getSleepersResponse).readEntity(SleepersResponse.class).getSleepers();
- }
-
- protected Response getSleepersResponse(Map<String, Object> data) throws LoginException {
- LoginInfo login = login();
- return getClient().target(config.getBaseUri()).path(Endpoints.sleeper()).queryParam(PARAM_KEY, login.getKey())
- .request(MediaType.APPLICATION_JSON_TYPE).get();
- }
-
- @Override
- public FamilyStatus getFamilyStatus() {
- return getSessionResponse(this::getFamilyStatusResponse).readEntity(FamilyStatus.class);
- }
-
- protected Response getFamilyStatusResponse(Map<String, Object> data) throws LoginException {
- LoginInfo login = login();
- return getClient().target(config.getBaseUri()).path(Endpoints.bed()).path(Endpoints.familyStatus())
- .queryParam(PARAM_KEY, login.getKey()).request(MediaType.APPLICATION_JSON_TYPE).get();
- }
-
- @Override
- public PauseMode getPauseMode(String bedId) throws BedNotFoundException {
- Map<String, Object> data = new HashMap<>();
- data.put(DATA_BED_ID, bedId);
-
- Response response = getSessionResponse(this::getPauseModeResponse, data);
-
- if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily())) {
- throw new BedNotFoundException(response.readEntity(Failure.class));
- }
-
- return response.readEntity(PauseMode.class);
- }
-
- protected Response getPauseModeResponse(Map<String, Object> data) throws LoginException {
- LoginInfo login = login();
- return getClient().target(config.getBaseUri()).path(Endpoints.bed()).path(data.get(DATA_BED_ID).toString())
- .path(Endpoints.pauseMode()).queryParam(PARAM_KEY, login.getKey())
- .request(MediaType.APPLICATION_JSON_TYPE).get();
- }
-
- protected boolean isUnauthorized(Response response) {
- return Status.UNAUTHORIZED.getStatusCode() == response.getStatusInfo().getStatusCode();
- }
-
- protected synchronized void resetLogin() {
- loginInfo = null;
- }
-
- protected Response getSessionResponse(Request request) {
- return getSessionResponse(request, Collections.emptyMap());
- }
-
- protected Response getSessionResponse(Request request, Map<String, Object> data) {
- try {
- Response response = request.execute(data);
-
- if (isUnauthorized(response)) {
- // session timed out
- response.close();
- resetLogin();
- response = request.execute(data);
- }
-
- return response;
- } catch (LoginException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
-
- @Override
- protected Client createClient() {
- // setup Gson (de)serialization
- GsonProvider<Object> gsonProvider = new GsonProvider<>(getGson());
- clientBuilder.register(gsonProvider);
-
- // turn on logging if requested
- if (config.isLogging()) {
- clientBuilder.register(new LoggingFilter(Logger.getLogger(SleepIQImpl.class.getName()), true));
- }
-
- return clientBuilder.build();
- }
-
- @FunctionalInterface
- public static interface Request {
- public Response execute(Map<String, Object> data) throws LoginException;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.util.function.Function;
-
-/**
- * Abstract type adapter for jsr310 date-time types.
- *
- * @author Christophe Bornet
- */
-abstract class DateTimeTypeAdapter<T> extends TemporalTypeAdapter<T> {
-
- DateTimeTypeAdapter(Function<String, T> parseFunction) {
- super(parseFunction);
- }
-
- @Override
- public String preProcess(String in) {
- if (in.endsWith("+0000")) {
- return in.substring(0, in.length()-5) + "Z";
- }
- return in;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.Duration;
-
-/**
- * Type adapter for jsr310 {@link Duration} class.
- *
- * @author Christophe Bornet
- */
-public class DurationTypeAdapter extends TemporalTypeAdapter<Duration> {
-
- public DurationTypeAdapter() {
- super(Duration::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.Instant;
-
-/**
- * Type adapter for jsr310 {@link Instant} class.
- *
- * @author Christophe Bornet
- */
-public class InstantTypeAdapter extends DateTimeTypeAdapter<Instant> {
-
- public InstantTypeAdapter() {
- super(Instant::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import com.google.gson.GsonBuilder;
-
-import java.time.*;
-
-/**
- * Helper methods to register JSR310 type adapters.
- *
- * @author Christophe Bornet
- */
-public class JSR310TypeAdapters {
-
- private JSR310TypeAdapters() {
- }
-
- public static GsonBuilder registerDurationTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(Duration.class, new DurationTypeAdapter());
- }
-
- public static GsonBuilder registerInstantTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(Instant.class, new InstantTypeAdapter());
- }
-
- public static GsonBuilder registerLocalDateTimeTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter());
- }
-
- public static GsonBuilder registerLocalDateTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter());
- }
-
- public static GsonBuilder registerLocalTimeTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(LocalTime.class, new LocalTimeTypeAdapter());
- }
-
- public static GsonBuilder registerMonthDayTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(MonthDay.class, new MonthDayTypeAdapter());
- }
-
- public static GsonBuilder registerOffsetDateTimeTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter());
- }
-
- public static GsonBuilder registerOffsetTimeTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(OffsetTime.class, new OffsetTimeTypeAdapter());
- }
-
- public static GsonBuilder registerPeriodTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(Period.class, new PeriodTypeAdapter());
- }
-
- public static GsonBuilder registerYearMonthTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(YearMonth.class, new YearMonthTypeAdapter());
- }
-
- public static GsonBuilder registerYearTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(Year.class, new YearTypeAdapter());
- }
-
- public static GsonBuilder registerZonedDateTimeTypeAdapter(GsonBuilder gsonBuilder) {
- return gsonBuilder.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeTypeAdapter());
- }
-
-
- /**
- * Helper method to register all the available JSR310 adapters at once.
- * @param gsonBuilder the gsonBuilder on which all the JSR310 adapters must be registered.
- * @return the gsonBuilder with the JSR310 adapters registered.
- */
- public static GsonBuilder registerJSR310TypeAdapters(GsonBuilder gsonBuilder) {
- registerDurationTypeAdapter(gsonBuilder);
- registerInstantTypeAdapter(gsonBuilder);
- registerLocalDateTimeTypeAdapter(gsonBuilder);
- registerLocalDateTypeAdapter(gsonBuilder);
- registerLocalTimeTypeAdapter(gsonBuilder);
- registerMonthDayTypeAdapter(gsonBuilder);
- registerOffsetDateTimeTypeAdapter(gsonBuilder);
- registerOffsetTimeTypeAdapter(gsonBuilder);
- registerPeriodTypeAdapter(gsonBuilder);
- registerYearMonthTypeAdapter(gsonBuilder);
- registerYearTypeAdapter(gsonBuilder);
- registerZonedDateTimeTypeAdapter(gsonBuilder);
-
- return gsonBuilder;
- }
-
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.LocalDateTime;
-
-/**
- * Type adapter for jsr310 {@link LocalDateTime} class.
- *
- * @author Christophe Bornet
- */
-public class LocalDateTimeTypeAdapter extends DateTimeTypeAdapter<LocalDateTime> {
-
- public LocalDateTimeTypeAdapter() {
- super(LocalDateTime::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.LocalDate;
-
-/**
- * Type adapter for jsr310 {@link LocalDate} class.
- *
- * @author Christophe Bornet
- */
-public class LocalDateTypeAdapter extends TemporalTypeAdapter<LocalDate> {
-
- public LocalDateTypeAdapter() {
- super(LocalDate::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.LocalTime;
-
-/**
- * Type adapter for jsr310 {@link LocalTime} class.
- *
- * @author Christophe Bornet
- */
-public class LocalTimeTypeAdapter extends TemporalTypeAdapter<LocalTime> {
-
- public LocalTimeTypeAdapter() {
- super(LocalTime::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.MonthDay;
-
-/**
- * Type adapter for jsr310 {@link MonthDay} class.
- *
- * @author Christophe Bornet
- */
-public class MonthDayTypeAdapter extends TemporalTypeAdapter<MonthDay> {
-
- public MonthDayTypeAdapter() {
- super(MonthDay::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.OffsetDateTime;
-
-/**
- * Type adapter for jsr310 {@link OffsetDateTime} class.
- *
- * @author Christophe Bornet
- */
-public class OffsetDateTimeTypeAdapter extends DateTimeTypeAdapter<OffsetDateTime> {
-
- public OffsetDateTimeTypeAdapter() {
- super(OffsetDateTime::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.OffsetTime;
-
-/**
- * Type adapter for jsr310 {@link OffsetTime} class.
- *
- * @author Christophe Bornet
- */
-public class OffsetTimeTypeAdapter extends TemporalTypeAdapter<OffsetTime> {
-
- public OffsetTimeTypeAdapter() {
- super(OffsetTime::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.Period;
-
-/**
- * Type adapter for jsr310 {@link Period} class.
- *
- * @author Christophe Bornet
- */
-public class PeriodTypeAdapter extends TemporalTypeAdapter<Period> {
-
- public PeriodTypeAdapter() {
- super(Period::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.io.IOException;
-import java.util.Objects;
-import java.util.function.Function;
-
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
-import com.google.gson.stream.JsonWriter;
-
-/**
- * Abstract type adapter for jsr310 date-time types.
- *
- * @author Christophe Bornet
- */
-abstract class TemporalTypeAdapter<T> extends TypeAdapter<T> {
-
- Function<String, T> parseFunction;
-
- TemporalTypeAdapter(Function<String, T> parseFunction) {
- Objects.requireNonNull(parseFunction);
- this.parseFunction = parseFunction;
- }
-
- @Override
- public void write(JsonWriter out, T value) throws IOException {
- if (value == null) {
- out.nullValue();
- } else {
- out.value(value.toString());
- }
- }
-
- @Override
- public T read(JsonReader in) throws IOException {
- if (in.peek() == JsonToken.NULL) {
- in.nextNull();
- return null;
- }
- String temporalString = preProcess(in.nextString());
- return parseFunction.apply(temporalString);
- }
-
- public String preProcess(String in) {
- return in;
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import org.openhab.binding.sleepiq.api.model.TimeSince;
-
-public class TimeSinceTypeAdapter extends TemporalTypeAdapter<TimeSince>
-{
- public TimeSinceTypeAdapter()
- {
- super(TimeSince::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.YearMonth;
-
-/**
- * Type adapter for jsr310 {@link YearMonth} class.
- *
- * @author Christophe Bornet
- */
-public class YearMonthTypeAdapter extends TemporalTypeAdapter<YearMonth> {
-
- public YearMonthTypeAdapter() {
- super(YearMonth::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.Year;
-
-/**
- * Type adapter for jsr310 {@link Year} class.
- *
- * @author Christophe Bornet
- */
-public class YearTypeAdapter extends TemporalTypeAdapter<Year> {
-
- public YearTypeAdapter() {
- super(Year::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2016 Gson Type Adapter Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Imported from https://github.com/google-gson/typeadapters/tree/master/jsr310/src
- * and repackaged to avoid the default package.
- */
-package org.openhab.binding.sleepiq.api.impl.typeadapters;
-
-import java.time.ZonedDateTime;
-
-/**
- * Type adapter for jsr310 {@link ZonedDateTime} class.
- *
- * @author Christophe Bornet
- */
-public class ZonedDateTimeTypeAdapter extends DateTimeTypeAdapter<ZonedDateTime> {
-
- public ZonedDateTimeTypeAdapter() {
- super(ZonedDateTime::parse);
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import java.time.ZonedDateTime;
-
-import com.google.gson.annotations.SerializedName;
-
-public class Bed
-{
- private ZonedDateTime registrationDate;
- private String sleeperRightId;
- private String base;
- private Long returnRequestStatus;
- private String size;
- private String name;
- private String serial;
- @SerializedName("isKidsBed")
- private Boolean kidsBed;
- private Boolean dualSleep;
- private String bedId;
- private Long status;
- private String sleeperLeftId;
- private String version;
- private String accountId;
- private String timezone;
- private String model;
- private ZonedDateTime purchaseDate;
- private String macAddress;
- private String sku;
- @SerializedName("zipcode")
- private String zipCode;
- private String reference;
-
- public ZonedDateTime getRegistrationDate()
- {
- return registrationDate;
- }
-
- public void setRegistrationDate(ZonedDateTime registrationDate)
- {
- this.registrationDate = registrationDate;
- }
-
- public Bed withRegistrationDate(ZonedDateTime registrationDate)
- {
- setRegistrationDate(registrationDate);
- return this;
- }
-
- public String getSleeperRightId()
- {
- return sleeperRightId;
- }
-
- public void setSleeperRightId(String sleeperRightId)
- {
- this.sleeperRightId = sleeperRightId;
- }
-
- public Bed withSleeperRightId(String sleeperRightId)
- {
- setSleeperRightId(sleeperRightId);
- return this;
- }
-
- public String getBase()
- {
- return base;
- }
-
- public void setBase(String base)
- {
- this.base = base;
- }
-
- public Bed withBase(String base)
- {
- setBase(base);
- return this;
- }
-
- public Long getReturnRequestStatus()
- {
- return returnRequestStatus;
- }
-
- public void setReturnRequestStatus(Long returnRequestStatus)
- {
- this.returnRequestStatus = returnRequestStatus;
- }
-
- public Bed withReturnRequestStatus(Long returnRequestStatus)
- {
- setReturnRequestStatus(returnRequestStatus);
- return this;
- }
-
- public String getSize()
- {
- return size;
- }
-
- public void setSize(String size)
- {
- this.size = size;
- }
-
- public Bed withSize(String size)
- {
- setSize(size);
- return this;
- }
-
- public String getName()
- {
- return name;
- }
-
- public void setName(String name)
- {
- this.name = name;
- }
-
- public Bed withName(String name)
- {
- setName(name);
- return this;
- }
-
- public String getSerial()
- {
- return serial;
- }
-
- public void setSerial(String serial)
- {
- this.serial = serial;
- }
-
- public Bed withSerial(String serial)
- {
- setSerial(serial);
- return this;
- }
-
- public Boolean isKidsBed()
- {
- return kidsBed;
- }
-
- public void setKidsBed(Boolean kidsBed)
- {
- this.kidsBed = kidsBed;
- }
-
- public Bed withKidsBed(Boolean kidsBed)
- {
- setKidsBed(kidsBed);
- return this;
- }
-
- public Boolean isDualSleep()
- {
- return dualSleep;
- }
-
- public void setDualSleep(Boolean dualSleep)
- {
- this.dualSleep = dualSleep;
- }
-
- public Bed withDualSleep(Boolean dualSleep)
- {
- setDualSleep(dualSleep);
- return this;
- }
-
- public String getBedId()
- {
- return bedId;
- }
-
- public void setBedId(String bedId)
- {
- this.bedId = bedId;
- }
-
- public Bed withBedId(String bedId)
- {
- setBedId(bedId);
- return this;
- }
-
- public Long getStatus()
- {
- return status;
- }
-
- public void setStatus(Long status)
- {
- this.status = status;
- }
-
- public Bed withStatus(Long status)
- {
- setStatus(status);
- return this;
- }
-
- public String getSleeperLeftId()
- {
- return sleeperLeftId;
- }
-
- public void setSleeperLeftId(String sleeperLeftId)
- {
- this.sleeperLeftId = sleeperLeftId;
- }
-
- public Bed withSleeperLeftId(String sleeperLeftId)
- {
- setSleeperLeftId(sleeperLeftId);
- return this;
- }
-
- public String getVersion()
- {
- return version;
- }
-
- public void setVersion(String version)
- {
- this.version = version;
- }
-
- public Bed withVersion(String version)
- {
- setVersion(version);
- return this;
- }
-
- public String getAccountId()
- {
- return accountId;
- }
-
- public void setAccountId(String accountId)
- {
- this.accountId = accountId;
- }
-
- public Bed withAccountId(String accountId)
- {
- setAccountId(accountId);
- return this;
- }
-
- public String getTimezone()
- {
- return timezone;
- }
-
- public void setTimezone(String timezone)
- {
- this.timezone = timezone;
- }
-
- public Bed withTimezone(String timezone)
- {
- setTimezone(timezone);
- return this;
- }
-
- public String getModel()
- {
- return model;
- }
-
- public void setModel(String model)
- {
- this.model = model;
- }
-
- public Bed withModel(String model)
- {
- setModel(model);
- return this;
- }
-
- public ZonedDateTime getPurchaseDate()
- {
- return purchaseDate;
- }
-
- public void setPurchaseDate(ZonedDateTime purchaseDate)
- {
- this.purchaseDate = purchaseDate;
- }
-
- public Bed withPurchaseDate(ZonedDateTime purchaseDate)
- {
- setPurchaseDate(purchaseDate);
- return this;
- }
-
- public String getMacAddress()
- {
- return macAddress;
- }
-
- public void setMacAddress(String macAddress)
- {
- this.macAddress = macAddress;
- }
-
- public Bed withMacAddress(String macAddress)
- {
- setMacAddress(macAddress);
- return this;
- }
-
- public String getSku()
- {
- return sku;
- }
-
- public void setSku(String sku)
- {
- this.sku = sku;
- }
-
- public Bed withSku(String sku)
- {
- setSku(sku);
- return this;
- }
-
- public String getZipCode()
- {
- return zipCode;
- }
-
- public void setZipCode(String zipCode)
- {
- this.zipCode = zipCode;
- }
-
- public Bed withZipCode(String zipCode)
- {
- setZipCode(zipCode);
- return this;
- }
-
- public String getReference()
- {
- return reference;
- }
-
- public void setReference(String reference)
- {
- this.reference = reference;
- }
-
- public Bed withReference(String reference)
- {
- setReference(reference);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((bedId == null) ? 0 : bedId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof Bed))
- {
- return false;
- }
- Bed other = (Bed)obj;
- if (bedId == null)
- {
- if (other.bedId != null)
- {
- return false;
- }
- }
- else if (!bedId.equals(other.bedId))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("Bed [registrationDate=");
- builder.append(registrationDate);
- builder.append(", sleeperRightId=");
- builder.append(sleeperRightId);
- builder.append(", base=");
- builder.append(base);
- builder.append(", returnRequestStatus=");
- builder.append(returnRequestStatus);
- builder.append(", size=");
- builder.append(size);
- builder.append(", name=");
- builder.append(name);
- builder.append(", serial=");
- builder.append(serial);
- builder.append(", kidsBed=");
- builder.append(kidsBed);
- builder.append(", dualSleep=");
- builder.append(dualSleep);
- builder.append(", bedId=");
- builder.append(bedId);
- builder.append(", status=");
- builder.append(status);
- builder.append(", sleeperLeftId=");
- builder.append(sleeperLeftId);
- builder.append(", version=");
- builder.append(version);
- builder.append(", accountId=");
- builder.append(accountId);
- builder.append(", timezone=");
- builder.append(timezone);
- builder.append(", model=");
- builder.append(model);
- builder.append(", purchaseDate=");
- builder.append(purchaseDate);
- builder.append(", macAddress=");
- builder.append(macAddress);
- builder.append(", sku=");
- builder.append(sku);
- builder.append(", zipCode=");
- builder.append(zipCode);
- builder.append(", reference=");
- builder.append(reference);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import com.google.gson.annotations.SerializedName;
-
-public class BedSideStatus
-{
- @SerializedName("isInBed")
- private Boolean inBed;
- private String alertDetailedMessage;
- private Integer sleepNumber;
- private Long alertId;
- private TimeSince lastLink;
- private Integer pressure; // appears to be in kPa
-
- public Boolean isInBed()
- {
- return inBed;
- }
-
- public void setInBed(Boolean inBed)
- {
- this.inBed = inBed;
- }
-
- public BedSideStatus withInBed(Boolean inBed)
- {
- setInBed(inBed);
- return this;
- }
-
- public String getAlertDetailedMessage()
- {
- return alertDetailedMessage;
- }
-
- public void setAlertDetailedMessage(String alertDetailedMessage)
- {
- this.alertDetailedMessage = alertDetailedMessage;
- }
-
- public BedSideStatus withAlertDetailedMessage(String alertDetailedMessage)
- {
- setAlertDetailedMessage(alertDetailedMessage);
- return this;
- }
-
- public Integer getSleepNumber()
- {
- return sleepNumber;
- }
-
- public void setSleepNumber(Integer sleepNumber)
- {
- this.sleepNumber = sleepNumber;
- }
-
- public BedSideStatus withSleepNumber(Integer sleepNumber)
- {
- setSleepNumber(sleepNumber);
- return this;
- }
-
- public Long getAlertId()
- {
- return alertId;
- }
-
- public void setAlertId(Long alertId)
- {
- this.alertId = alertId;
- }
-
- public BedSideStatus withAlertId(Long alertId)
- {
- setAlertId(alertId);
- return this;
- }
-
- public TimeSince getLastLink()
- {
- return lastLink;
- }
-
- public void setLastLink(TimeSince lastLink)
- {
- this.lastLink = lastLink;
- }
-
- public BedSideStatus withLastLink(TimeSince lastLink)
- {
- setLastLink(lastLink);
- return this;
- }
-
- public Integer getPressure()
- {
- return pressure;
- }
-
- public void setPressure(Integer pressure)
- {
- this.pressure = pressure;
- }
-
- public BedSideStatus withPressure(Integer pressure)
- {
- setPressure(pressure);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + ((alertDetailedMessage == null) ? 0 : alertDetailedMessage.hashCode());
- result = prime * result + ((alertId == null) ? 0 : alertId.hashCode());
- result = prime * result + ((inBed == null) ? 0 : inBed.hashCode());
- result = prime * result + ((lastLink == null) ? 0 : lastLink.hashCode());
- result = prime * result + ((pressure == null) ? 0 : pressure.hashCode());
- result = prime * result + ((sleepNumber == null) ? 0 : sleepNumber.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof BedSideStatus))
- {
- return false;
- }
- BedSideStatus other = (BedSideStatus)obj;
- if (alertDetailedMessage == null)
- {
- if (other.alertDetailedMessage != null)
- {
- return false;
- }
- }
- else if (!alertDetailedMessage.equals(other.alertDetailedMessage))
- {
- return false;
- }
- if (alertId == null)
- {
- if (other.alertId != null)
- {
- return false;
- }
- }
- else if (!alertId.equals(other.alertId))
- {
- return false;
- }
- if (inBed == null)
- {
- if (other.inBed != null)
- {
- return false;
- }
- }
- else if (!inBed.equals(other.inBed))
- {
- return false;
- }
- if (lastLink == null)
- {
- if (other.lastLink != null)
- {
- return false;
- }
- }
- else if (!lastLink.equals(other.lastLink))
- {
- return false;
- }
- if (pressure == null)
- {
- if (other.pressure != null)
- {
- return false;
- }
- }
- else if (!pressure.equals(other.pressure))
- {
- return false;
- }
- if (sleepNumber == null)
- {
- if (other.sleepNumber != null)
- {
- return false;
- }
- }
- else if (!sleepNumber.equals(other.sleepNumber))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("BedSideStatus [inBed=");
- builder.append(inBed);
- builder.append(", alertDetailedMessage=");
- builder.append(alertDetailedMessage);
- builder.append(", sleepNumber=");
- builder.append(sleepNumber);
- builder.append(", alertId=");
- builder.append(alertId);
- builder.append(", lastLink=");
- builder.append(lastLink);
- builder.append(", pressure=");
- builder.append(pressure);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-public class BedStatus
-{
- private Long status;
- private String bedId;
- private BedSideStatus leftSide;
- private BedSideStatus rightSide;
-
- public Long getStatus()
- {
- return status;
- }
-
- public void setStatus(Long status)
- {
- this.status = status;
- }
-
- public BedStatus withStatus(Long status)
- {
- setStatus(status);
- return this;
- }
-
- public String getBedId()
- {
- return bedId;
- }
-
- public void setBedId(String bedId)
- {
- this.bedId = bedId;
- }
-
- public BedStatus withBedId(String bedId)
- {
- setBedId(bedId);
- return this;
- }
-
- public BedSideStatus getLeftSide()
- {
- return leftSide;
- }
-
- public void setLeftSide(BedSideStatus leftSide)
- {
- this.leftSide = leftSide;
- }
-
- public BedStatus withLeftSide(BedSideStatus leftSide)
- {
- setLeftSide(leftSide);
- return this;
- }
-
- public BedSideStatus getRightSide()
- {
- return rightSide;
- }
-
- public void setRightSide(BedSideStatus rightSide)
- {
- this.rightSide = rightSide;
- }
-
- public BedStatus withRightSide(BedSideStatus rightSide)
- {
- setRightSide(rightSide);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((bedId == null) ? 0 : bedId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof BedStatus))
- {
- return false;
- }
- BedStatus other = (BedStatus)obj;
- if (bedId == null)
- {
- if (other.bedId != null)
- {
- return false;
- }
- }
- else if (!bedId.equals(other.bedId))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("BedStatus [status=");
- builder.append(status);
- builder.append(", bedId=");
- builder.append(bedId);
- builder.append(", leftSide=");
- builder.append(leftSide);
- builder.append(", rightSide=");
- builder.append(rightSide);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import java.util.List;
-
-public class BedsResponse
-{
- private List<Bed> beds;
-
- public List<Bed> getBeds()
- {
- return beds;
- }
-
- public void setBeds(List<Bed> beds)
- {
- this.beds = beds;
- }
-
- public BedsResponse withBeds(List<Bed> beds)
- {
- setBeds(beds);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((beds == null) ? 0 : beds.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof BedsResponse))
- {
- return false;
- }
- BedsResponse other = (BedsResponse)obj;
- if (beds == null)
- {
- if (other.beds != null)
- {
- return false;
- }
- }
- else if (!beds.equals(other.beds))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("BedsResponse [beds=");
- builder.append(beds);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import com.google.gson.annotations.SerializedName;
-
-public class Error
-{
- @SerializedName("Code")
- private Long code;
- @SerializedName("Message")
- private String message;
-
- public Long getCode()
- {
- return code;
- }
-
- public void setCode(Long code)
- {
- this.code = code;
- }
-
- public Error withCode(Long code)
- {
- setCode(code);
- return this;
- }
-
- public String getMessage()
- {
- return message;
- }
-
- public void setMessage(String message)
- {
- this.message = message;
- }
-
- public Error withMessage(String message)
- {
- setMessage(message);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((code == null) ? 0 : code.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof Error))
- {
- return false;
- }
- Error other = (Error)obj;
- if (code == null)
- {
- if (other.code != null)
- {
- return false;
- }
- }
- else if (!code.equals(other.code))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("Error [code=");
- builder.append(code);
- builder.append(", message=");
- builder.append(message);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import com.google.gson.annotations.SerializedName;
-
-public class Failure
-{
- @SerializedName("Error")
- private Error error;
-
- public Error getError()
- {
- return error;
- }
-
- public void setError(Error error)
- {
- this.error = error;
- }
-
- public Failure withError(Error error)
- {
- setError(error);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((error == null) ? 0 : error.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof Failure))
- {
- return false;
- }
- Failure other = (Failure)obj;
- if (error == null)
- {
- if (other.error != null)
- {
- return false;
- }
- }
- else if (!error.equals(other.error))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("Failure [error=");
- builder.append(error);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import java.util.List;
-
-public class FamilyStatus
-{
- private List<BedStatus> beds;
-
- public List<BedStatus> getBeds()
- {
- return beds;
- }
-
- public void setBeds(List<BedStatus> beds)
- {
- this.beds = beds;
- }
-
- public FamilyStatus withBeds(List<BedStatus> beds)
- {
- setBeds(beds);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((beds == null) ? 0 : beds.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof FamilyStatus))
- {
- return false;
- }
- FamilyStatus other = (FamilyStatus)obj;
- if (beds == null)
- {
- if (other.beds != null)
- {
- return false;
- }
- }
- else if (!beds.equals(other.beds))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("FamilyStatus [beds=");
- builder.append(beds);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-public class LoginInfo
-{
- private String userId;
- private String key;
- private Long registrationState;
- private Long edpLoginStatus;
- private String edpLoginMessage;
-
- public String getUserId()
- {
- return userId;
- }
-
- public void setUserId(String userId)
- {
- this.userId = userId;
- }
-
- public LoginInfo withUserId(String userId)
- {
- setUserId(userId);
- return this;
- }
-
- public String getKey()
- {
- return key;
- }
-
- public void setKey(String key)
- {
- this.key = key;
- }
-
- public LoginInfo withKey(String key)
- {
- setKey(key);
- return this;
- }
-
- public Long getRegistrationState()
- {
- return registrationState;
- }
-
- public void setRegistrationState(Long registrationState)
- {
- this.registrationState = registrationState;
- }
-
- public LoginInfo withRegistrationState(Long registrationState)
- {
- setRegistrationState(registrationState);
- return this;
- }
-
- public Long getEdpLoginStatus()
- {
- return edpLoginStatus;
- }
-
- public void setEdpLoginStatus(Long edpLoginStatus)
- {
- this.edpLoginStatus = edpLoginStatus;
- }
-
- public LoginInfo withEdpLoginStatus(Long edpLoginStatus)
- {
- setEdpLoginStatus(edpLoginStatus);
- return this;
- }
-
- public String getEdpLoginMessage()
- {
- return edpLoginMessage;
- }
-
- public void setEdpLoginMessage(String edpLoginMessage)
- {
- this.edpLoginMessage = edpLoginMessage;
- }
-
- public LoginInfo withEdpLoginMessage(String edpLoginMessage)
- {
- setEdpLoginMessage(edpLoginMessage);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((key == null) ? 0 : key.hashCode());
- result = prime * result + (int)(registrationState ^ (registrationState >>> 32));
- result = prime * result + ((userId == null) ? 0 : userId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof LoginInfo))
- {
- return false;
- }
- LoginInfo other = (LoginInfo)obj;
- if (key == null)
- {
- if (other.key != null)
- {
- return false;
- }
- }
- else if (!key.equals(other.key))
- {
- return false;
- }
- if (!registrationState.equals(other.registrationState))
- {
- return false;
- }
- if (userId == null)
- {
- if (other.userId != null)
- {
- return false;
- }
- }
- else if (!userId.equals(other.userId))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("LoginInfo [userId=");
- builder.append(userId);
- builder.append(", key=");
- builder.append(key);
- builder.append(", registrationState=");
- builder.append(registrationState);
- builder.append(", edpLoginStatus=");
- builder.append(edpLoginStatus);
- builder.append(", edpLoginMessage=");
- builder.append(edpLoginMessage);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-public class LoginRequest
-{
- private String login;
- private String password;
-
- public String getLogin()
- {
- return login;
- }
-
- public void setLogin(String login)
- {
- this.login = login;
- }
-
- public LoginRequest withLogin(String login)
- {
- setLogin(login);
- return this;
- }
-
- public String getPassword()
- {
- return password;
- }
-
- public void setPassword(String password)
- {
- this.password = password;
- }
-
- public LoginRequest withPassword(String password)
- {
- setPassword(password);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((login == null) ? 0 : login.hashCode());
- result = prime * result + ((password == null) ? 0 : password.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof LoginRequest))
- {
- return false;
- }
- LoginRequest other = (LoginRequest)obj;
- if (login == null)
- {
- if (other.login != null)
- {
- return false;
- }
- }
- else if (!login.equals(other.login))
- {
- return false;
- }
- if (password == null)
- {
- if (other.password != null)
- {
- return false;
- }
- }
- else if (!password.equals(other.password))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("LoginRequest [login=");
- builder.append(login);
- builder.append(", password=");
- builder.append(password);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-public class PauseMode
-{
- private String accountId;
- private String bedId;
- private String pauseMode;
-
- public String getAccountId()
- {
- return accountId;
- }
-
- public void setAccountId(String accountId)
- {
- this.accountId = accountId;
- }
-
- public PauseMode withAccountId(String accountId)
- {
- setAccountId(accountId);
- return this;
- }
-
- public String getBedId()
- {
- return bedId;
- }
-
- public void setBedId(String bedId)
- {
- this.bedId = bedId;
- }
-
- public PauseMode withBedId(String bedId)
- {
- setBedId(bedId);
- return this;
- }
-
- public String getPauseMode()
- {
- return pauseMode;
- }
-
- public void setPauseMode(String pauseMode)
- {
- this.pauseMode = pauseMode;
- }
-
- public PauseMode withPauseMode(String pauseMode)
- {
- setPauseMode(pauseMode);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((accountId == null) ? 0 : accountId.hashCode());
- result = prime * result + ((bedId == null) ? 0 : bedId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof PauseMode))
- {
- return false;
- }
- PauseMode other = (PauseMode)obj;
- if (accountId == null)
- {
- if (other.accountId != null)
- {
- return false;
- }
- }
- else if (!accountId.equals(other.accountId))
- {
- return false;
- }
- if (bedId == null)
- {
- if (other.bedId != null)
- {
- return false;
- }
- }
- else if (!bedId.equals(other.bedId))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("PauseMode [accountId=");
- builder.append(accountId);
- builder.append(", bedId=");
- builder.append(bedId);
- builder.append(", pauseMode=");
- builder.append(pauseMode);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import com.google.gson.annotations.SerializedName;
-
-public class Sleeper
-{
- private String firstName;
- private Boolean active;
- private Boolean emailValidated;
- @SerializedName("isChild")
- private Boolean child;
- private String bedId;
- private String birthYear;
- private String zipCode;
- private String timezone;
- @SerializedName("isMale")
- private Boolean male;
- private Integer weight; // lbs
- private String duration;
- private String sleeperId;
- private Integer height; // inches
- private Long licenseVersion;
- private String username;
- private Integer birthMonth; // 0-based; 12 means not entered?
- private Integer sleepGoal;
- @SerializedName("isAccountOwner")
- private Boolean accountOwner;
- private String accountId;
- private String email;
- private String avatar;
- private String lastLogin; // should be ZonedDateTime but provider passes string "null" when missing
- private Integer side; // 0=left; 1=right
-
- public String getFirstName()
- {
- return firstName;
- }
-
- public void setFirstName(String firstName)
- {
- this.firstName = firstName;
- }
-
- public Sleeper withFirstName(String firstName)
- {
- setFirstName(firstName);
- return this;
- }
-
- public Boolean isActive()
- {
- return active;
- }
-
- public void setActive(Boolean active)
- {
- this.active = active;
- }
-
- public Sleeper withActive(Boolean active)
- {
- setActive(active);
- return this;
- }
-
- public Boolean isEmailValidated()
- {
- return emailValidated;
- }
-
- public void setEmailValidated(Boolean emailValidated)
- {
- this.emailValidated = emailValidated;
- }
-
- public Sleeper withEmailValidated(Boolean emailValidated)
- {
- setEmailValidated(emailValidated);
- return this;
- }
-
- public Boolean isChild()
- {
- return child;
- }
-
- public void setChild(Boolean child)
- {
- this.child = child;
- }
-
- public Sleeper withChild(Boolean child)
- {
- setChild(child);
- return this;
- }
-
- public String getBedId()
- {
- return bedId;
- }
-
- public void setBedId(String bedId)
- {
- this.bedId = bedId;
- }
-
- public Sleeper withBedId(String bedId)
- {
- setBedId(bedId);
- return this;
- }
-
- public String getBirthYear()
- {
- return birthYear;
- }
-
- public void setBirthYear(String birthYear)
- {
- this.birthYear = birthYear;
- }
-
- public Sleeper withBirthYear(String birthYear)
- {
- setBirthYear(birthYear);
- return this;
- }
-
- public String getZipCode()
- {
- return zipCode;
- }
-
- public void setZipCode(String zipCode)
- {
- this.zipCode = zipCode;
- }
-
- public Sleeper withZipCode(String zipCode)
- {
- setZipCode(zipCode);
- return this;
- }
-
- public String getTimezone()
- {
- return timezone;
- }
-
- public void setTimezone(String timezone)
- {
- this.timezone = timezone;
- }
-
- public Sleeper withTimezone(String timezone)
- {
- setTimezone(timezone);
- return this;
- }
-
- public Boolean isMale()
- {
- return male;
- }
-
- public void setMale(Boolean male)
- {
- this.male = male;
- }
-
- public Sleeper withMale(Boolean male)
- {
- setMale(male);
- return this;
- }
-
- public Integer getWeight()
- {
- return weight;
- }
-
- public void setWeight(Integer weight)
- {
- this.weight = weight;
- }
-
- public Sleeper withWeight(Integer weight)
- {
- setWeight(weight);
- return this;
- }
-
- public String getDuration()
- {
- return duration;
- }
-
- public void setDuration(String duration)
- {
- this.duration = duration;
- }
-
- public Sleeper withDuration(String duration)
- {
- setDuration(duration);
- return this;
- }
-
- public String getSleeperId()
- {
- return sleeperId;
- }
-
- public void setSleeperId(String sleeperId)
- {
- this.sleeperId = sleeperId;
- }
-
- public Sleeper withSleeperId(String sleeperId)
- {
- setSleeperId(sleeperId);
- return this;
- }
-
- public Integer getHeight()
- {
- return height;
- }
-
- public void setHeight(Integer height)
- {
- this.height = height;
- }
-
- public Sleeper withHeight(Integer height)
- {
- setHeight(height);
- return this;
- }
-
- public Long getLicenseVersion()
- {
- return licenseVersion;
- }
-
- public void setLicenseVersion(Long licenseVersion)
- {
- this.licenseVersion = licenseVersion;
- }
-
- public Sleeper withLicenseVersion(Long licenseVersion)
- {
- setLicenseVersion(licenseVersion);
- return this;
- }
-
- public String getUsername()
- {
- return username;
- }
-
- public void setUsername(String username)
- {
- this.username = username;
- }
-
- public Sleeper withUsername(String username)
- {
- setUsername(username);
- return this;
- }
-
- public Integer getBirthMonth()
- {
- return birthMonth;
- }
-
- public void setBirthMonth(Integer birthMonth)
- {
- this.birthMonth = birthMonth;
- }
-
- public Sleeper withBirthMonth(Integer birthMonth)
- {
- setBirthMonth(birthMonth);
- return this;
- }
-
- public Integer getSleepGoal()
- {
- return sleepGoal;
- }
-
- public void setSleepGoal(Integer sleepGoal)
- {
- this.sleepGoal = sleepGoal;
- }
-
- public Sleeper withSleepGoal(Integer sleepGoal)
- {
- setSleepGoal(sleepGoal);
- return this;
- }
-
- public Boolean isAccountOwner()
- {
- return accountOwner;
- }
-
- public void setAccountOwner(Boolean accountOwner)
- {
- this.accountOwner = accountOwner;
- }
-
- public Sleeper withAccountOwner(Boolean accountOwner)
- {
- setAccountOwner(accountOwner);
- return this;
- }
-
- public String getAccountId()
- {
- return accountId;
- }
-
- public void setAccountId(String accountId)
- {
- this.accountId = accountId;
- }
-
- public Sleeper withAccountId(String accountId)
- {
- setAccountId(accountId);
- return this;
- }
-
- public String getEmail()
- {
- return email;
- }
-
- public void setEmail(String email)
- {
- this.email = email;
- }
-
- public Sleeper withEmail(String email)
- {
- setEmail(email);
- return this;
- }
-
- public String getAvatar()
- {
- return avatar;
- }
-
- public void setAvatar(String avatar)
- {
- this.avatar = avatar;
- }
-
- public Sleeper withAvatar(String avatar)
- {
- setAvatar(avatar);
- return this;
- }
-
- public String getLastLogin()
- {
- return lastLogin;
- }
-
- public void setLastLogin(String lastLogin)
- {
- this.lastLogin = lastLogin;
- }
-
- public Sleeper withLastLogin(String lastLogin)
- {
- setLastLogin(lastLogin);
- return this;
- }
-
- public Integer getSide()
- {
- return side;
- }
-
- public void setSide(Integer side)
- {
- this.side = side;
- }
-
- public Sleeper withSide(Integer side)
- {
- setSide(side);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((sleeperId == null) ? 0 : sleeperId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof Sleeper))
- {
- return false;
- }
- Sleeper other = (Sleeper)obj;
- if (sleeperId == null)
- {
- if (other.sleeperId != null)
- {
- return false;
- }
- }
- else if (!sleeperId.equals(other.sleeperId))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("Sleeper [firstName=");
- builder.append(firstName);
- builder.append(", active=");
- builder.append(active);
- builder.append(", emailValidated=");
- builder.append(emailValidated);
- builder.append(", child=");
- builder.append(child);
- builder.append(", bedId=");
- builder.append(bedId);
- builder.append(", birthYear=");
- builder.append(birthYear);
- builder.append(", zipCode=");
- builder.append(zipCode);
- builder.append(", timezone=");
- builder.append(timezone);
- builder.append(", male=");
- builder.append(male);
- builder.append(", weight=");
- builder.append(weight);
- builder.append(", duration=");
- builder.append(duration);
- builder.append(", sleeperId=");
- builder.append(sleeperId);
- builder.append(", height=");
- builder.append(height);
- builder.append(", licenseVersion=");
- builder.append(licenseVersion);
- builder.append(", username=");
- builder.append(username);
- builder.append(", birthMonth=");
- builder.append(birthMonth);
- builder.append(", sleepGoal=");
- builder.append(sleepGoal);
- builder.append(", accountOwner=");
- builder.append(accountOwner);
- builder.append(", accountId=");
- builder.append(accountId);
- builder.append(", email=");
- builder.append(email);
- builder.append(", avatar=");
- builder.append(avatar);
- builder.append(", lastLogin=");
- builder.append(lastLogin);
- builder.append(", side=");
- builder.append(side);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import java.util.List;
-
-public class SleepersResponse
-{
- private List<Sleeper> sleepers;
-
- public List<Sleeper> getSleepers()
- {
- return sleepers;
- }
-
- public void setSleepers(List<Sleeper> sleepers)
- {
- this.sleepers = sleepers;
- }
-
- public SleepersResponse withSleepers(List<Sleeper> sleepers)
- {
- setSleepers(sleepers);
- return this;
- }
-
- @Override
- public int hashCode()
- {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((sleepers == null) ? 0 : sleepers.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (obj == null)
- {
- return false;
- }
- if (!(obj instanceof SleepersResponse))
- {
- return false;
- }
- SleepersResponse other = (SleepersResponse)obj;
- if (sleepers == null)
- {
- if (other.sleepers != null)
- {
- return false;
- }
- }
- else if (!sleepers.equals(other.sleepers))
- {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
- builder.append("SleepersResponse [sleepers=");
- builder.append(sleepers);
- builder.append("]");
- return builder.toString();
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import java.time.Duration;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class TimeSince {
- private static final Pattern PATTERN = Pattern.compile("(([0-9]+) d )?([0-9]{2}):([0-9]{2}):([0-9]{2})",
- Pattern.CASE_INSENSITIVE);
-
- private Duration duration;
-
- public Duration getDuration() {
- return duration;
- }
-
- public void setDuration(Duration duration) {
- this.duration = duration == null ? null : duration.abs();
- }
-
- public TimeSince withDuration(long days, long hours, long minutes, long seconds) {
- return withDuration(Duration.ofSeconds(TimeUnit.DAYS.toSeconds(days) + TimeUnit.HOURS.toSeconds(hours)
- + TimeUnit.MINUTES.toSeconds(minutes) + seconds));
- }
-
- public TimeSince withDuration(Duration duration) {
- setDuration(duration);
- return this;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((duration == null) ? 0 : duration.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof TimeSince)) {
- return false;
- }
- TimeSince other = (TimeSince) obj;
- if (duration == null) {
- if (other.duration != null) {
- return false;
- }
- } else if (!duration.equals(other.duration)) {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- long totalDays = duration.toDays();
- long totalHours = duration.toHours();
- long totalMinutes = duration.toMinutes();
- long totalSeconds = duration.getSeconds();
-
- long hours = totalHours - TimeUnit.DAYS.toHours(totalDays);
- long minutes = totalMinutes - TimeUnit.HOURS.toMinutes(totalHours);
- long seconds = totalSeconds - TimeUnit.MINUTES.toSeconds(totalMinutes);
-
- if (totalDays > 0) {
- return String.format("%d d %02d:%02d:%02d", totalDays, hours, minutes, seconds);
- }
-
- return String.format("%02d:%02d:%02d", hours, minutes, seconds);
- }
-
- public static TimeSince parse(CharSequence text) {
- Objects.requireNonNull(text, "text");
-
- Matcher matcher = PATTERN.matcher(text);
- if (!matcher.matches()) {
- return new TimeSince().withDuration(Duration.ZERO);
- }
-
- String dayMatch = matcher.group(2);
- String hourMatch = matcher.group(3);
- String minuteMatch = matcher.group(4);
- String secondMatch = matcher.group(5);
-
- StringBuilder sb = new StringBuilder("P");
- if (dayMatch != null) {
- sb.append(dayMatch).append('D');
- }
- sb.append('T').append(hourMatch).append('H').append(minuteMatch).append('M').append(secondMatch).append('S');
-
- return new TimeSince().withDuration(Duration.parse(sb.toString()));
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.io.FileReader;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class BedSideStatusTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- BedSideStatus bedSideStatus = new BedSideStatus().withAlertDetailedMessage("No Alert").withAlertId(0L)
- .withInBed(false).withLastLink(new TimeSince().withDuration(3, 5, 4, 38)).withPressure(573)
- .withSleepNumber(55);
- assertEquals(readJson("bed-side-status.json"), gson.toJson(bedSideStatus));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("bed-side-status.json"))) {
- BedSideStatus bedSideStatus = gson.fromJson(reader, BedSideStatus.class);
- assertEquals("No Alert", bedSideStatus.getAlertDetailedMessage());
- assertEquals(Long.valueOf(0L), bedSideStatus.getAlertId());
- assertFalse(bedSideStatus.isInBed());
- assertEquals(new TimeSince().withDuration(3, 5, 4, 38), bedSideStatus.getLastLink());
- assertEquals(Integer.valueOf(573), bedSideStatus.getPressure());
- assertEquals(Integer.valueOf(55), bedSideStatus.getSleepNumber());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.io.FileReader;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class BedStatusTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- BedStatus bedStatus = new BedStatus().withBedId("-9999999999999999999")
- .withLeftSide(new BedSideStatus().withInBed(true)).withRightSide(new BedSideStatus().withInBed(false))
- .withStatus(1L);
- assertEquals(readJson("bed-status.json"), gson.toJson(bedStatus));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("bed-status.json"))) {
- BedStatus bedStatus = gson.fromJson(reader, BedStatus.class);
- assertEquals("-9999999999999999999", bedStatus.getBedId());
- assertEquals(Long.valueOf(1L), bedStatus.getStatus());
-
- BedSideStatus leftSide = bedStatus.getLeftSide();
- assertNotNull(leftSide);
- assertTrue(leftSide.isInBed());
-
- BedSideStatus rightSide = bedStatus.getRightSide();
- assertNotNull(rightSide);
- assertFalse(rightSide.isInBed());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.io.FileReader;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class BedTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- Bed bed = new Bed().withAccountId("-8888888888888888888").withBase("MODULAR").withBedId("-9999999999999999999")
- .withDualSleep(true).withKidsBed(false).withMacAddress("AABBCCDDEEFF").withModel("P5").withName("Bed")
- .withPurchaseDate(ZonedDateTime.of(2017, 2, 2, 0, 0, 1, 0, ZoneId.of("Z").normalized()))
- .withReference("55555555555-5")
- .withRegistrationDate(ZonedDateTime.of(2017, 2, 17, 2, 14, 10, 0, ZoneId.of("Z").normalized()))
- .withReturnRequestStatus(0L).withSerial("").withSize("QUEEN").withSku("QP5")
- .withSleeperLeftId("-2222222222222222222").withSleeperRightId("-1111111111111111111").withStatus(1L)
- .withTimezone("US/Pacific").withVersion("").withZipCode("90210");
- assertEquals(readJson("bed.json"), gson.toJson(bed));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("bed.json"))) {
- Bed bed = gson.fromJson(reader, Bed.class);
- assertEquals("-8888888888888888888", bed.getAccountId());
- assertEquals("MODULAR", bed.getBase());
- assertEquals("-9999999999999999999", bed.getBedId());
- assertEquals(true, bed.isDualSleep());
- assertEquals(false, bed.isKidsBed());
- assertEquals("AABBCCDDEEFF", bed.getMacAddress());
- assertEquals("P5", bed.getModel());
- assertEquals("Bed", bed.getName());
- assertEquals(ZonedDateTime.of(2017, 2, 2, 0, 0, 1, 0, ZoneId.of("Z").normalized()), bed.getPurchaseDate());
- assertEquals("55555555555-5", bed.getReference());
- assertEquals(ZonedDateTime.of(2017, 2, 17, 2, 14, 10, 0, ZoneId.of("Z").normalized()),
- bed.getRegistrationDate());
- assertEquals(Long.valueOf(0L), bed.getReturnRequestStatus());
- assertEquals("", bed.getSerial());
- assertEquals("QUEEN", bed.getSize());
- assertEquals("QP5", bed.getSku());
- assertEquals("-2222222222222222222", bed.getSleeperLeftId());
- assertEquals("-1111111111111111111", bed.getSleeperRightId());
- assertEquals(Long.valueOf(1L), bed.getStatus());
- assertEquals("US/Pacific", bed.getTimezone());
- assertEquals("", bed.getVersion());
- assertEquals("90210", bed.getZipCode());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.io.FileReader;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class BedsResponseTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- BedsResponse bedsResponse = new BedsResponse()
- .withBeds(Arrays.asList(new Bed().withName("Bed1"), new Bed().withName("Bed2")));
- assertEquals(readJson("beds-response.json"), gson.toJson(bedsResponse));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("beds-response.json"))) {
- BedsResponse bedsResponse = gson.fromJson(reader, BedsResponse.class);
-
- List<Bed> beds = bedsResponse.getBeds();
- assertNotNull(beds);
- assertEquals(2, beds.size());
- assertEquals("Bed1", beds.get(0).getName());
- assertEquals("Bed2", beds.get(1).getName());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.io.FileReader;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class FamilyStatusTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- FamilyStatus familyStatus = new FamilyStatus().withBeds(Arrays.asList(new BedStatus().withStatus(1L)));
- assertEquals(readJson("family-status.json"), gson.toJson(familyStatus));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("family-status.json"))) {
- FamilyStatus familyStatus = gson.fromJson(reader, FamilyStatus.class);
-
- List<BedStatus> beds = familyStatus.getBeds();
- assertNotNull(beds);
- assertEquals(1, beds.size());
- assertEquals(Long.valueOf(1L), beds.get(0).getStatus());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.io.FileReader;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class PauseModeTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- PauseMode pauseMode = new PauseMode().withAccountId("-8888888888888888888").withBedId("-9999999999999999999")
- .withPauseMode("off");
- assertEquals(readJson("pause-mode.json"), gson.toJson(pauseMode));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("pause-mode.json"))) {
- PauseMode pauseMode = gson.fromJson(reader, PauseMode.class);
- assertEquals("-8888888888888888888", pauseMode.getAccountId());
- assertEquals("-9999999999999999999", pauseMode.getBedId());
- assertEquals("off", pauseMode.getPauseMode());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.io.FileReader;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class SleeperTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- Sleeper sleeper = new Sleeper().withAccountId("-5555555555555555555").withAccountOwner(true).withActive(true)
- .withAvatar("").withBedId("-9999999999999999999").withBirthMonth(6).withBirthYear("1970")
- .withChild(false).withDuration("").withEmail("alice@domain.com").withEmailValidated(true)
- .withFirstName("Alice").withHeight(64).withLastLogin("2017-02-17 20:19:36 CST").withLicenseVersion(6L)
- .withMale(false).withSide(1).withSleeperId("-1111111111111111111").withSleepGoal(450)
- .withTimezone("US/Pacific").withUsername("alice@domain.com").withWeight(110).withZipCode("90210");
- assertEquals(readJson("sleeper.json"), gson.toJson(sleeper));
- }
-
- @Test
- public void testSerializeLastLoginNull() throws Exception {
- Sleeper sleeper = new Sleeper().withLastLogin("null");
- assertEquals(readJson("sleeper-lastlogin-null.json"), gson.toJson(sleeper));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("sleeper.json"))) {
- Sleeper sleeper = gson.fromJson(reader, Sleeper.class);
- assertEquals("-5555555555555555555", sleeper.getAccountId());
- assertEquals(true, sleeper.isAccountOwner());
- assertEquals(true, sleeper.isActive());
- assertEquals("", sleeper.getAvatar());
- assertEquals("-9999999999999999999", sleeper.getBedId());
- assertEquals(Integer.valueOf(6), sleeper.getBirthMonth());
- assertEquals("1970", sleeper.getBirthYear());
- assertEquals(false, sleeper.isChild());
- assertEquals("", sleeper.getDuration());
- assertEquals("alice@domain.com", sleeper.getEmail());
- assertEquals(true, sleeper.isEmailValidated());
- assertEquals("Alice", sleeper.getFirstName());
- assertEquals(Integer.valueOf(64), sleeper.getHeight());
- assertEquals("2017-02-17 20:19:36 CST", sleeper.getLastLogin());
- assertEquals(Long.valueOf(6L), sleeper.getLicenseVersion());
- assertEquals(false, sleeper.isMale());
- assertEquals(Integer.valueOf(1), sleeper.getSide());
- assertEquals("-1111111111111111111", sleeper.getSleeperId());
- assertEquals(Integer.valueOf(450), sleeper.getSleepGoal());
- assertEquals("US/Pacific", sleeper.getTimezone());
- assertEquals("alice@domain.com", sleeper.getUsername());
- assertEquals(Integer.valueOf(110), sleeper.getWeight());
- assertEquals("90210", sleeper.getZipCode());
- }
- }
-
- @Test
- public void testDeserializeLastLoginNull() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("sleeper-lastlogin-null.json"))) {
- Sleeper sleeper = gson.fromJson(reader, Sleeper.class);
- assertEquals("null", sleeper.getLastLogin());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.io.FileReader;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.openhab.binding.sleepiq.api.impl.GsonGenerator;
-import org.openhab.binding.sleepiq.api.test.AbstractTest;
-
-import com.google.gson.Gson;
-
-public class SleepersResponseTest extends AbstractTest {
- private static Gson gson;
-
- @BeforeAll
- public static void setUpBeforeClass() {
- gson = GsonGenerator.create(true);
- }
-
- @Test
- public void testSerializeAllFields() throws Exception {
- SleepersResponse sleepersResponse = new SleepersResponse()
- .withSleepers(Arrays.asList(new Sleeper().withFirstName("Alice"), new Sleeper().withFirstName("Bob")));
- assertEquals(readJson("sleepers-response.json"), gson.toJson(sleepersResponse));
- }
-
- @Test
- public void testDeserializeAllFields() throws Exception {
- try (FileReader reader = new FileReader(getTestDataFile("sleepers-response.json"))) {
- SleepersResponse sleepersResponse = gson.fromJson(reader, SleepersResponse.class);
-
- List<Sleeper> sleepers = sleepersResponse.getSleepers();
- assertNotNull(sleepers);
- assertEquals(2, sleepers.size());
- assertEquals("Alice", sleepers.get(0).getFirstName());
- assertEquals("Bob", sleepers.get(1).getFirstName());
- }
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.model;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.time.Duration;
-
-import org.junit.jupiter.api.Test;
-
-public class TimeSinceTest {
- @Test
- public void testWithDuration() {
- assertEquals(new TimeSince().withDuration(0, 0, 0, 0).getDuration(),
- new TimeSince().withDuration(Duration.parse("PT00H00M00S")).getDuration());
- assertEquals(new TimeSince().withDuration(0, 2, 3, 4).getDuration(),
- new TimeSince().withDuration(Duration.parse("PT02H03M04S")).getDuration());
- assertEquals(new TimeSince().withDuration(0, 12, 34, 56).getDuration(),
- new TimeSince().withDuration(Duration.parse("PT12H34M56S")).getDuration());
- assertEquals(new TimeSince().withDuration(1, 2, 3, 4).getDuration(),
- new TimeSince().withDuration(Duration.parse("P1DT02H03M04S")).getDuration());
- assertEquals(new TimeSince().withDuration(12, 23, 34, 45).getDuration(),
- new TimeSince().withDuration(Duration.parse("P12DT23H34M45S")).getDuration());
- }
-
- @Test
- public void testToString() {
- assertEquals("00:00:00", new TimeSince().withDuration(Duration.parse("PT00H00M00S")).toString());
- assertEquals("02:03:04", new TimeSince().withDuration(Duration.parse("PT02H03M04S")).toString());
- assertEquals("12:34:56", new TimeSince().withDuration(Duration.parse("PT12H34M56S")).toString());
- assertEquals("1 d 02:03:04", new TimeSince().withDuration(Duration.parse("P1DT02H03M04S")).toString());
- assertEquals("12 d 23:34:45", new TimeSince().withDuration(Duration.parse("P12DT23H34M45S")).toString());
- }
-
- @Test
- public void testParse() {
- assertEquals(Duration.parse("PT00H00M00S"), TimeSince.parse("00:00:00").getDuration());
- assertEquals(Duration.parse("PT2H3M4S"), TimeSince.parse("02:03:04").getDuration());
- assertEquals(Duration.parse("PT12H34M56S"), TimeSince.parse("12:34:56").getDuration());
- assertEquals(Duration.parse("P1DT2H3M4S"), TimeSince.parse("1 d 02:03:04").getDuration());
- assertEquals(Duration.parse("P12DT23H34M45S"), TimeSince.parse("12 d 23:34:45").getDuration());
- }
-}
+++ /dev/null
-/*
- * Copyright 2017 Gregory Moyer
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openhab.binding.sleepiq.api.test;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public abstract class AbstractTest {
- private static final String RESOURCES_PATH = "src/test/resources/";
-
- protected File getTestDataFile(String name) {
- return getTestDataPath(name).toFile();
- }
-
- protected Path getTestDataPath(String name) {
- String packageName = this.getClass().getPackage().getName();
-
- List<String> paths = new ArrayList<>();
- paths.addAll(Arrays.asList(packageName.split("\\.")));
- paths.add(name);
-
- return Paths.get(RESOURCES_PATH, paths.toArray(new String[paths.size()]));
- }
-
- protected String readJson(String jsonFileName) throws IOException {
- return String.join("\n", Files.readAllLines(getTestDataPath(jsonFileName)));
- }
-}
+++ /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.sleepiq.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-
-import com.google.gson.Gson;
-
-/**
- * JSON reader/writer for Jersey using GSON.
- *
- * @author Simon Kaufmann - Initial contribution
- *
- * @param <T>
- */
-@Provider
-@Produces(MediaType.APPLICATION_JSON)
-@Consumes(MediaType.APPLICATION_JSON)
-public class GsonProvider<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {
-
- private final Gson gson;
-
- public GsonProvider(Gson gson) {
- this.gson = gson;
- }
-
- @Override
- public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
- return -1;
- }
-
- @Override
- public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
- return true;
- }
-
- @Override
- public void writeTo(T object, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
- MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
- throws IOException, WebApplicationException {
- try (OutputStream stream = entityStream) {
- entityStream.write(gson.toJson(object).getBytes(StandardCharsets.UTF_8));
- entityStream.flush();
- }
- }
-
- @Override
- public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
- return true;
- }
-
- @Override
- public T readFrom(Class<T> type, Type genericType, Annotation[] annotations, MediaType mediaType,
- MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
- throws IOException, WebApplicationException {
- try (InputStreamReader reader = new InputStreamReader(entityStream, StandardCharsets.UTF_8)) {
- return gson.fromJson(reader, type);
- }
- }
-}
public static final ThingTypeUID THING_TYPE_CLOUD = new ThingTypeUID(BINDING_ID, "cloud");
// generic thing types
- // public static final ThingTypeUID THING_TYPE_SINGLE_BED = new ThingTypeUID(BINDING_ID, "singleBed");
public static final ThingTypeUID THING_TYPE_DUAL_BED = new ThingTypeUID(BINDING_ID, "dualBed");
// List of all Channel ids
- // public static final String CHANNEL_BED_IN_BED = "bed#inBed";
public static final String CHANNEL_LEFT_IN_BED = "left#inBed";
public static final String CHANNEL_RIGHT_IN_BED = "right#inBed";
- // public static final String CHANNEL_BED_SLEEP_NUMBER = "bed#sleepNumber";
public static final String CHANNEL_LEFT_SLEEP_NUMBER = "left#sleepNumber";
public static final String CHANNEL_RIGHT_SLEEP_NUMBER = "right#sleepNumber";
- // public static final String CHANNEL_BED_PRESSURE = "bed#pressure";
public static final String CHANNEL_LEFT_PRESSURE = "left#pressure";
public static final String CHANNEL_RIGHT_PRESSURE = "right#pressure";
- // public static final String CHANNEL_BED_LAST_LINK = "bed#lastLink";
public static final String CHANNEL_LEFT_LAST_LINK = "left#lastLink";
public static final String CHANNEL_RIGHT_LAST_LINK = "right#lastLink";
- // public static final String CHANNEL_BED_ALERT_ID = "bed#alertId";
public static final String CHANNEL_LEFT_ALERT_ID = "left#alertId";
public static final String CHANNEL_RIGHT_ALERT_ID = "right#alertId";
- // public static final String CHANNEL_BED_ALERT_DETAILED_MESSAGE = "bed#alertDetailedMessage";
public static final String CHANNEL_LEFT_ALERT_DETAILED_MESSAGE = "left#alertDetailedMessage";
public static final String CHANNEL_RIGHT_ALERT_DETAILED_MESSAGE = "right#alertDetailedMessage";
+ public static final String CHANNEL_LEFT_FIRST_NAME = "left#firstName";
+ public static final String CHANNEL_RIGHT_FIRST_NAME = "right#firstName";
+
+ public static final String CHANNEL_LEFT_SLEEP_GOAL_MINUTES = "left#sleepGoalMinutes";
+ public static final String CHANNEL_RIGHT_SLEEP_GOAL_MINUTES = "right#sleepGoalMinutes";
+
+ public static final String CHANNEL_LEFT_PRIVACY_MODE = "left#privacyMode";
+ public static final String CHANNEL_RIGHT_PRIVACY_MODE = "right#privacyMode";
+
+ public static final String CHANNEL_LEFT_TODAY_SLEEP_IQ = "left#todaySleepIQ";
+ public static final String CHANNEL_RIGHT_TODAY_SLEEP_IQ = "right#todaySleepIQ";
+
+ public static final String CHANNEL_LEFT_TODAY_AVG_HEART_RATE = "left#todayAverageHeartRate";
+ public static final String CHANNEL_RIGHT_TODAY_AVG_HEART_RATE = "right#todayAverageHeartRate";
+
+ public static final String CHANNEL_LEFT_TODAY_AVG_RESPIRATION_RATE = "left#todayAverageRespirationRate";
+ public static final String CHANNEL_RIGHT_TODAY_AVG_RESPIRATION_RATE = "right#todayAverageRespirationRate";
+
+ public static final String CHANNEL_LEFT_TODAY_MESSAGE = "left#todayMessage";
+ public static final String CHANNEL_RIGHT_TODAY_MESSAGE = "right#todayMessage";
+
+ public static final String CHANNEL_LEFT_TODAY_SLEEP_DURATION_SECONDS = "left#todaySleepDurationSeconds";
+ public static final String CHANNEL_RIGHT_TODAY_SLEEP_DURATION_SECONDS = "right#todaySleepDurationSeconds";
+
+ public static final String CHANNEL_LEFT_MONTHLY_SLEEP_IQ = "left#monthlySleepIQ";
+ public static final String CHANNEL_RIGHT_MONTHLY_SLEEP_IQ = "right#monthlySleepIQ";
+
+ public static final String CHANNEL_LEFT_MONTHLY_AVG_HEART_RATE = "left#monthlyAverageHeartRate";
+ public static final String CHANNEL_RIGHT_MONTHLY_AVG_HEART_RATE = "right#monthlyAverageHeartRate";
+
+ public static final String CHANNEL_LEFT_MONTHLY_AVG_RESPIRATION_RATE = "left#monthlyAverageRespirationRate";
+ public static final String CHANNEL_RIGHT_MONTHLY_AVG_RESPIRATION_RATE = "right#monthlyAverageRespirationRate";
+
// List of non-standard Properties
public static final String PROPERTY_BASE = "base";
public static final String PROPERTY_KIDS_BED = "kidsBed";
public static final String PROPERTY_PURCHASE_DATE = "purchaseDate";
public static final String PROPERTY_SIZE = "size";
public static final String PROPERTY_SKU = "sku";
-
- private SleepIQBindingConstants() {
- // utility class
- }
}
*/
package org.openhab.binding.sleepiq.internal;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
/**
* The {@link SleepIQConfigStatusMessage} defines the keys to be used for configuration status messages.
*
* @author Gregory Moyer - Initial contribution
*
*/
+@NonNullByDefault
public interface SleepIQConfigStatusMessage {
public static final String USERNAME_MISSING = "missing-username-configuration";
public static final String PASSWORD_MISSING = "missing-password-configuration";
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import javax.ws.rs.client.ClientBuilder;
-
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.sleepiq.internal.discovery.SleepIQBedDiscoveryService;
import org.openhab.binding.sleepiq.internal.handler.SleepIQCloudHandler;
import org.openhab.binding.sleepiq.internal.handler.SleepIQDualBedHandler;
import org.openhab.core.config.discovery.DiscoveryService;
+import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
*
* @author Gregory Moyer - Initial contribution
*/
+@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.sleepiq")
public class SleepIQHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Collections
private final Logger logger = LoggerFactory.getLogger(SleepIQHandlerFactory.class);
- private final ClientBuilder clientBuilder;
+ private final HttpClient httpClient;
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceReg = new HashMap<>();
@Activate
- public SleepIQHandlerFactory(@Reference ClientBuilder clientBuilder) {
- this.clientBuilder = clientBuilder;
+ public SleepIQHandlerFactory(@Reference HttpClientFactory httpClientFactory) {
+ this.httpClient = httpClientFactory.getCommonHttpClient();
}
@Override
}
@Override
- protected ThingHandler createHandler(final Thing thing) {
+ protected @Nullable ThingHandler createHandler(final Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
-
if (SleepIQCloudHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) {
logger.debug("Creating SleepIQ cloud thing handler");
- SleepIQCloudHandler cloudHandler = new SleepIQCloudHandler((Bridge) thing, clientBuilder);
+ SleepIQCloudHandler cloudHandler = new SleepIQCloudHandler((Bridge) thing, httpClient);
registerBedDiscoveryService(cloudHandler);
return cloudHandler;
} else if (SleepIQDualBedHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) {
logger.debug("Creating SleepIQ dual bed thing handler");
return new SleepIQDualBedHandler(thing);
}
-
return null;
}
@Override
protected void removeHandler(final ThingHandler thingHandler) {
logger.debug("Removing SleepIQ thing handler");
-
if (thingHandler instanceof SleepIQCloudHandler) {
unregisterBedDiscoveryService((SleepIQCloudHandler) thingHandler);
}
--- /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.sleepiq.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link BedNotFoundException} is thrown when a bedId is missing or invalid.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class BedNotFoundException extends SleepIQException {
+ private static final long serialVersionUID = 1L;
+
+ public BedNotFoundException(String message) {
+ super(message);
+ }
+}
--- /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.sleepiq.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link CommunicationException} is thrown when there's an error communicating with
+ * the sleepiq service.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class CommunicationException extends SleepIQException {
+ private static final long serialVersionUID = 1L;
+
+ public CommunicationException(String message) {
+ super(message);
+ }
+}
--- /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.sleepiq.internal.api;
+
+import java.net.URI;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * This class represents configuration parameters for using {@link SleepIQ}.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class Configuration {
+ private String username = "";
+ private String password = "";
+
+ private URI baseUri = URI.create("https://api.sleepiq.sleepnumber.com");
+
+ private boolean logging = false;
+
+ /**
+ * Get the username on the account.
+ *
+ * @return the username
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Set the username on the account. This should be the username used to
+ * register with SleepIQ.
+ *
+ * @param username
+ * the value to set
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Set the username on the account. This should be the username used to
+ * register with SleepIQ.
+ *
+ * @param username
+ * the value to set
+ * @return this configuration instance
+ */
+ public Configuration withUsername(String username) {
+ setUsername(username);
+ return this;
+ }
+
+ /**
+ * Get the password on the account.
+ *
+ * @return the password
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Set the password on the account. This should be the password used to
+ * register with SleepIQ.
+ *
+ * @param password
+ * the value to set
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Set the password on the account. This should be the password used to
+ * register with SleepIQ.
+ *
+ * @param password
+ * the value to set
+ * @return this configuration instance
+ */
+ public Configuration withPassword(String password) {
+ setPassword(password);
+ return this;
+ }
+
+ /**
+ * Get the base URI of the SleepIQ cloud service.
+ *
+ * @return the base URI
+ */
+ public URI getBaseUri() {
+ return baseUri;
+ }
+
+ /**
+ * Set the base URI of the SleepIQ cloud service. It is unlikely that this
+ * will need to be changed from its default value.
+ *
+ * @param baseUri
+ * the value to set
+ */
+ public void setBaseUri(URI baseUri) {
+ this.baseUri = baseUri;
+ }
+
+ /**
+ * Set the base URI of the SleepIQ cloud service. It is unlikely that this
+ * will need to be changed from its default value.
+ *
+ * @param baseUri
+ * the value to set
+ * @return this configuration instance
+ */
+ public Configuration withBaseUri(URI baseUri) {
+ setBaseUri(baseUri);
+ return this;
+ }
+
+ /**
+ * Get the logging flag.
+ *
+ * @return the logging flag
+ */
+ public boolean isLogging() {
+ return logging;
+ }
+
+ /**
+ * Set the logging flag. When this is set to <code>true</code>, all requests
+ * and responses will be logged at the {@link Level#INFO} level. <b>This
+ * includes usernames and passwords!</b>
+ *
+ * @param logging
+ * the value to set
+ */
+ public void setLogging(boolean logging) {
+ this.logging = logging;
+ }
+
+ /**
+ * Set the logging flag. When this is set to <code>true</code>, all requests
+ * and responses will be logged at the {@link Level#INFO} level. <b>This
+ * includes usernames and passwords!</b>
+ *
+ * @param logging
+ * the value to set
+ * @return this configuration instance
+ */
+ public Configuration withLogging(boolean logging) {
+ setLogging(logging);
+ return this;
+ }
+}
--- /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.sleepiq.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link LoginException} is thrown when there's a failure to log
+ * into the sleepiq service.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class LoginException extends SleepIQException {
+ private static final long serialVersionUID = 1L;
+
+ public LoginException(String message) {
+ super(message);
+ }
+}
--- /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.sleepiq.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link LoginException} is thrown when a badly formatted response is
+ * received from the sleepiq service.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class ResponseFormatException extends SleepIQException {
+ private static final long serialVersionUID = 1L;
+
+ public ResponseFormatException(String message) {
+ super(message);
+ }
+}
--- /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.sleepiq.internal.api;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.sleepiq.internal.api.dto.Bed;
+import org.openhab.binding.sleepiq.internal.api.dto.FamilyStatusResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.LoginInfo;
+import org.openhab.binding.sleepiq.internal.api.dto.PauseModeResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepDataResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.Sleeper;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+import org.openhab.binding.sleepiq.internal.api.enums.SleepDataInterval;
+import org.openhab.binding.sleepiq.internal.api.impl.SleepIQImpl;
+
+/**
+ * This interface is the main API to access the SleepIQ system.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public interface SleepIQ {
+ /**
+ * Login to the {@link Configuration configured} account. This method is not
+ * required to be called before other methods because all methods must
+ * ensure login before acting. However, when the only desired action is to
+ * login and not retrieve other data, this method is the most efficient
+ * option.
+ *
+ * @return basic information about the logged in user
+ * @throws UnauthorizedException
+ * if the credentials provided are not valid
+ * @throws LoginException
+ * if the login request fails for any reason other than bad
+ * credentials (including missing credentials)
+ */
+ public @Nullable LoginInfo login() throws LoginException, UnauthorizedException;
+
+ /**
+ * Get a list of beds connected to the account.
+ *
+ * @return the list of beds
+ * @throws LoginException
+ * if the login request fails for any reason other than bad
+ * credentials (including missing credentials)
+ * @throws SleepIQException
+ */
+ public List<Bed> getBeds() throws LoginException, SleepIQException, BedNotFoundException;
+
+ /**
+ * Get a list of sleepers registered to this account for beds or bed positions
+ * (left or right side).
+ *
+ * @return the list of sleepers
+ * @throws LoginException
+ * @throws SleepIQException
+ */
+ public List<Sleeper> getSleepers() throws LoginException, SleepIQException;
+
+ /**
+ * Get the status of all beds and all air chambers registered to this
+ * account.
+ *
+ * @return the complete status of beds on the account
+ * @throws LoginException
+ * @throws SleepIQException
+ */
+ public FamilyStatusResponse getFamilyStatus() throws LoginException, SleepIQException;
+
+ /**
+ * Get the Sleep Data for a sleeper registered to this account.
+ *
+ * @param sleeperId the sleeper Id to query
+ * @param interval The time period for which data is to be queried
+ * @return the Sleep Data
+ * @throws BedNotFoundException
+ * if the bed identifier was not found on the account
+ * @throws LoginException
+ * @throws SleepIQException
+ */
+ public SleepDataResponse getSleepData(String sleeperId, SleepDataInterval interval)
+ throws BedNotFoundException, LoginException, SleepIQException;
+
+ /**
+ * Get the status of "pause mode" (disabling SleepIQ data upload) for a
+ * specific bed. A bed in pause mode will send no information to the SleepIQ
+ * cloud services. For example, if a sleeper is in bed and disables SleepIQ
+ * (enables pause mode), the service will continue to report that the bed is
+ * occupied even after the sleeper exits the bed until pause mode is
+ * disabled.
+ *
+ * @return the status of pause mode for the specified bed
+ * @throws BedNotFoundException
+ * if the bed identifier was not found on the account
+ * @throws LoginException
+ * @throws SleepIQException
+ */
+ public PauseModeResponse getPauseMode(String bedId) throws BedNotFoundException, LoginException, SleepIQException;
+
+ /**
+ * Set the sleep number for a chamber of a bed
+ *
+ * @param bedId the unique identifier of the bed
+ * @param side thethe chamber of the bed
+ * @param sleepNumber the new sleep number
+ *
+ * @throws LoginException
+ * @throws SleepIQException
+ */
+ public void setSleepNumber(String bedId, Side side, int sleepNumber) throws LoginException, SleepIQException;
+
+ /**
+ * Set the pause (privacy) mode for a bed
+ *
+ * @param bedId the unique identifier of the bed
+ *
+ * @throws LoginException
+ * @throws SleepIQException
+ */
+ public void setPauseMode(String bedId, boolean command) throws LoginException, SleepIQException;
+
+ /**
+ * Create a default implementation instance of this interface. Each call to
+ * this method will create a new object.
+ *
+ * @param config the configuration to use for the new instance
+ * @param httpClient handle to the Jetty http client
+ * @return a concrete implementation of this interface
+ */
+ public static SleepIQ create(Configuration config, HttpClient httpClient) {
+ return new SleepIQImpl(config, httpClient);
+ }
+
+ /**
+ * Close down the cloud service
+ */
+ public void shutdown();
+}
--- /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.sleepiq.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link SleepIQException} is the base exception class from which other
+ * sleepiq exceptions are derived.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class SleepIQException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public SleepIQException(String message) {
+ super(message);
+ }
+}
--- /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.sleepiq.internal.api;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link UnauthorizedException} is thrown when a login to the sleepiq service
+ * is unauthorized to use the API.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class UnauthorizedException extends LoginException {
+ private static final long serialVersionUID = 1L;
+
+ public UnauthorizedException(String message) {
+ super(message);
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import java.time.ZonedDateTime;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link Bed} holds the bed response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class Bed {
+ private ZonedDateTime registrationDate;
+ private String sleeperRightId;
+ private String base;
+ private Long returnRequestStatus;
+ private String size;
+ private String name;
+ private String serial;
+ @SerializedName("isKidsBed")
+ private Boolean kidsBed;
+ private Boolean dualSleep;
+ private String bedId;
+ private Long status;
+ private String sleeperLeftId;
+ private String version;
+ private String accountId;
+ private String timezone;
+ private String model;
+ private ZonedDateTime purchaseDate;
+ private String macAddress;
+ private String sku;
+ @SerializedName("zipcode")
+ private String zipCode;
+ private String reference;
+
+ public ZonedDateTime getRegistrationDate() {
+ return registrationDate;
+ }
+
+ public void setRegistrationDate(ZonedDateTime registrationDate) {
+ this.registrationDate = registrationDate;
+ }
+
+ public Bed withRegistrationDate(ZonedDateTime registrationDate) {
+ setRegistrationDate(registrationDate);
+ return this;
+ }
+
+ public String getSleeperRightId() {
+ return sleeperRightId;
+ }
+
+ public void setSleeperRightId(String sleeperRightId) {
+ this.sleeperRightId = sleeperRightId;
+ }
+
+ public Bed withSleeperRightId(String sleeperRightId) {
+ setSleeperRightId(sleeperRightId);
+ return this;
+ }
+
+ public String getBase() {
+ return base;
+ }
+
+ public void setBase(String base) {
+ this.base = base;
+ }
+
+ public Bed withBase(String base) {
+ setBase(base);
+ return this;
+ }
+
+ public Long getReturnRequestStatus() {
+ return returnRequestStatus;
+ }
+
+ public void setReturnRequestStatus(Long returnRequestStatus) {
+ this.returnRequestStatus = returnRequestStatus;
+ }
+
+ public Bed withReturnRequestStatus(Long returnRequestStatus) {
+ setReturnRequestStatus(returnRequestStatus);
+ return this;
+ }
+
+ public String getSize() {
+ return size;
+ }
+
+ public void setSize(String size) {
+ this.size = size;
+ }
+
+ public Bed withSize(String size) {
+ setSize(size);
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Bed withName(String name) {
+ setName(name);
+ return this;
+ }
+
+ public String getSerial() {
+ return serial;
+ }
+
+ public void setSerial(String serial) {
+ this.serial = serial;
+ }
+
+ public Bed withSerial(String serial) {
+ setSerial(serial);
+ return this;
+ }
+
+ public Boolean isKidsBed() {
+ return kidsBed;
+ }
+
+ public void setKidsBed(Boolean kidsBed) {
+ this.kidsBed = kidsBed;
+ }
+
+ public Bed withKidsBed(Boolean kidsBed) {
+ setKidsBed(kidsBed);
+ return this;
+ }
+
+ public Boolean isDualSleep() {
+ return dualSleep;
+ }
+
+ public void setDualSleep(Boolean dualSleep) {
+ this.dualSleep = dualSleep;
+ }
+
+ public Bed withDualSleep(Boolean dualSleep) {
+ setDualSleep(dualSleep);
+ return this;
+ }
+
+ public String getBedId() {
+ return bedId;
+ }
+
+ public void setBedId(String bedId) {
+ this.bedId = bedId;
+ }
+
+ public Bed withBedId(String bedId) {
+ setBedId(bedId);
+ return this;
+ }
+
+ public Long getStatus() {
+ return status;
+ }
+
+ public void setStatus(Long status) {
+ this.status = status;
+ }
+
+ public Bed withStatus(Long status) {
+ setStatus(status);
+ return this;
+ }
+
+ public String getSleeperLeftId() {
+ return sleeperLeftId;
+ }
+
+ public void setSleeperLeftId(String sleeperLeftId) {
+ this.sleeperLeftId = sleeperLeftId;
+ }
+
+ public Bed withSleeperLeftId(String sleeperLeftId) {
+ setSleeperLeftId(sleeperLeftId);
+ return this;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public Bed withVersion(String version) {
+ setVersion(version);
+ return this;
+ }
+
+ public String getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(String accountId) {
+ this.accountId = accountId;
+ }
+
+ public Bed withAccountId(String accountId) {
+ setAccountId(accountId);
+ return this;
+ }
+
+ public String getTimezone() {
+ return timezone;
+ }
+
+ public void setTimezone(String timezone) {
+ this.timezone = timezone;
+ }
+
+ public Bed withTimezone(String timezone) {
+ setTimezone(timezone);
+ return this;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public Bed withModel(String model) {
+ setModel(model);
+ return this;
+ }
+
+ public ZonedDateTime getPurchaseDate() {
+ return purchaseDate;
+ }
+
+ public void setPurchaseDate(ZonedDateTime purchaseDate) {
+ this.purchaseDate = purchaseDate;
+ }
+
+ public Bed withPurchaseDate(ZonedDateTime purchaseDate) {
+ setPurchaseDate(purchaseDate);
+ return this;
+ }
+
+ public String getMacAddress() {
+ return macAddress;
+ }
+
+ public void setMacAddress(String macAddress) {
+ this.macAddress = macAddress;
+ }
+
+ public Bed withMacAddress(String macAddress) {
+ setMacAddress(macAddress);
+ return this;
+ }
+
+ public String getSku() {
+ return sku;
+ }
+
+ public void setSku(String sku) {
+ this.sku = sku;
+ }
+
+ public Bed withSku(String sku) {
+ setSku(sku);
+ return this;
+ }
+
+ public String getZipCode() {
+ return zipCode;
+ }
+
+ public void setZipCode(String zipCode) {
+ this.zipCode = zipCode;
+ }
+
+ public Bed withZipCode(String zipCode) {
+ setZipCode(zipCode);
+ return this;
+ }
+
+ public String getReference() {
+ return reference;
+ }
+
+ public void setReference(String reference) {
+ this.reference = reference;
+ }
+
+ public Bed withReference(String reference) {
+ setReference(reference);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((bedId == null) ? 0 : bedId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Bed)) {
+ return false;
+ }
+ Bed other = (Bed) obj;
+ if (bedId == null) {
+ if (other.bedId != null) {
+ return false;
+ }
+ } else if (!bedId.equals(other.bedId)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Bed [registrationDate=");
+ builder.append(registrationDate);
+ builder.append(", sleeperRightId=");
+ builder.append(sleeperRightId);
+ builder.append(", base=");
+ builder.append(base);
+ builder.append(", returnRequestStatus=");
+ builder.append(returnRequestStatus);
+ builder.append(", size=");
+ builder.append(size);
+ builder.append(", name=");
+ builder.append(name);
+ builder.append(", serial=");
+ builder.append(serial);
+ builder.append(", kidsBed=");
+ builder.append(kidsBed);
+ builder.append(", dualSleep=");
+ builder.append(dualSleep);
+ builder.append(", bedId=");
+ builder.append(bedId);
+ builder.append(", status=");
+ builder.append(status);
+ builder.append(", sleeperLeftId=");
+ builder.append(sleeperLeftId);
+ builder.append(", version=");
+ builder.append(version);
+ builder.append(", accountId=");
+ builder.append(accountId);
+ builder.append(", timezone=");
+ builder.append(timezone);
+ builder.append(", model=");
+ builder.append(model);
+ builder.append(", purchaseDate=");
+ builder.append(purchaseDate);
+ builder.append(", macAddress=");
+ builder.append(macAddress);
+ builder.append(", sku=");
+ builder.append(sku);
+ builder.append(", zipCode=");
+ builder.append(zipCode);
+ builder.append(", reference=");
+ builder.append(reference);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link BedSideStatus} holds the BedSideStatus response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class BedSideStatus {
+ @SerializedName("isInBed")
+ private Boolean inBed;
+ private String alertDetailedMessage;
+ private Integer sleepNumber;
+ private Long alertId;
+ private TimeSince lastLink;
+ private Integer pressure; // appears to be in kPa
+
+ public Boolean isInBed() {
+ return inBed;
+ }
+
+ public void setInBed(Boolean inBed) {
+ this.inBed = inBed;
+ }
+
+ public BedSideStatus withInBed(Boolean inBed) {
+ setInBed(inBed);
+ return this;
+ }
+
+ public String getAlertDetailedMessage() {
+ return alertDetailedMessage;
+ }
+
+ public void setAlertDetailedMessage(String alertDetailedMessage) {
+ this.alertDetailedMessage = alertDetailedMessage;
+ }
+
+ public BedSideStatus withAlertDetailedMessage(String alertDetailedMessage) {
+ setAlertDetailedMessage(alertDetailedMessage);
+ return this;
+ }
+
+ public Integer getSleepNumber() {
+ return sleepNumber;
+ }
+
+ public void setSleepNumber(Integer sleepNumber) {
+ this.sleepNumber = sleepNumber;
+ }
+
+ public BedSideStatus withSleepNumber(Integer sleepNumber) {
+ setSleepNumber(sleepNumber);
+ return this;
+ }
+
+ public Long getAlertId() {
+ return alertId;
+ }
+
+ public void setAlertId(Long alertId) {
+ this.alertId = alertId;
+ }
+
+ public BedSideStatus withAlertId(Long alertId) {
+ setAlertId(alertId);
+ return this;
+ }
+
+ public TimeSince getLastLink() {
+ return lastLink;
+ }
+
+ public void setLastLink(TimeSince lastLink) {
+ this.lastLink = lastLink;
+ }
+
+ public BedSideStatus withLastLink(TimeSince lastLink) {
+ setLastLink(lastLink);
+ return this;
+ }
+
+ public Integer getPressure() {
+ return pressure;
+ }
+
+ public void setPressure(Integer pressure) {
+ this.pressure = pressure;
+ }
+
+ public BedSideStatus withPressure(Integer pressure) {
+ setPressure(pressure);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((alertDetailedMessage == null) ? 0 : alertDetailedMessage.hashCode());
+ result = prime * result + ((alertId == null) ? 0 : alertId.hashCode());
+ result = prime * result + ((inBed == null) ? 0 : inBed.hashCode());
+ result = prime * result + ((lastLink == null) ? 0 : lastLink.hashCode());
+ result = prime * result + ((pressure == null) ? 0 : pressure.hashCode());
+ result = prime * result + ((sleepNumber == null) ? 0 : sleepNumber.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof BedSideStatus)) {
+ return false;
+ }
+ BedSideStatus other = (BedSideStatus) obj;
+ if (alertDetailedMessage == null) {
+ if (other.alertDetailedMessage != null) {
+ return false;
+ }
+ } else if (!alertDetailedMessage.equals(other.alertDetailedMessage)) {
+ return false;
+ }
+ if (alertId == null) {
+ if (other.alertId != null) {
+ return false;
+ }
+ } else if (!alertId.equals(other.alertId)) {
+ return false;
+ }
+ if (inBed == null) {
+ if (other.inBed != null) {
+ return false;
+ }
+ } else if (!inBed.equals(other.inBed)) {
+ return false;
+ }
+ if (lastLink == null) {
+ if (other.lastLink != null) {
+ return false;
+ }
+ } else if (!lastLink.equals(other.lastLink)) {
+ return false;
+ }
+ if (pressure == null) {
+ if (other.pressure != null) {
+ return false;
+ }
+ } else if (!pressure.equals(other.pressure)) {
+ return false;
+ }
+ if (sleepNumber == null) {
+ if (other.sleepNumber != null) {
+ return false;
+ }
+ } else if (!sleepNumber.equals(other.sleepNumber)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("BedSideStatus [inBed=");
+ builder.append(inBed);
+ builder.append(", alertDetailedMessage=");
+ builder.append(alertDetailedMessage);
+ builder.append(", sleepNumber=");
+ builder.append(sleepNumber);
+ builder.append(", alertId=");
+ builder.append(alertId);
+ builder.append(", lastLink=");
+ builder.append(lastLink);
+ builder.append(", pressure=");
+ builder.append(pressure);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+/**
+ * The {@link BedStatus} holds the BedStatus response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class BedStatus {
+ private Long status;
+ private String bedId;
+ private BedSideStatus leftSide;
+ private BedSideStatus rightSide;
+
+ public Long getStatus() {
+ return status;
+ }
+
+ public void setStatus(Long status) {
+ this.status = status;
+ }
+
+ public BedStatus withStatus(Long status) {
+ setStatus(status);
+ return this;
+ }
+
+ public String getBedId() {
+ return bedId;
+ }
+
+ public void setBedId(String bedId) {
+ this.bedId = bedId;
+ }
+
+ public BedStatus withBedId(String bedId) {
+ setBedId(bedId);
+ return this;
+ }
+
+ public BedSideStatus getLeftSide() {
+ return leftSide;
+ }
+
+ public void setLeftSide(BedSideStatus leftSide) {
+ this.leftSide = leftSide;
+ }
+
+ public BedStatus withLeftSide(BedSideStatus leftSide) {
+ setLeftSide(leftSide);
+ return this;
+ }
+
+ public BedSideStatus getRightSide() {
+ return rightSide;
+ }
+
+ public void setRightSide(BedSideStatus rightSide) {
+ this.rightSide = rightSide;
+ }
+
+ public BedStatus withRightSide(BedSideStatus rightSide) {
+ setRightSide(rightSide);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((bedId == null) ? 0 : bedId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof BedStatus)) {
+ return false;
+ }
+ BedStatus other = (BedStatus) obj;
+ if (bedId == null) {
+ if (other.bedId != null) {
+ return false;
+ }
+ } else if (!bedId.equals(other.bedId)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("BedStatus [status=");
+ builder.append(status);
+ builder.append(", bedId=");
+ builder.append(bedId);
+ builder.append(", leftSide=");
+ builder.append(leftSide);
+ builder.append(", rightSide=");
+ builder.append(rightSide);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import java.util.List;
+
+/**
+ * The {@link BedsResponse} holds the BedsResponse response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class BedsResponse {
+ private List<Bed> beds;
+
+ public List<Bed> getBeds() {
+ return beds;
+ }
+
+ public void setBeds(List<Bed> beds) {
+ this.beds = beds;
+ }
+
+ public BedsResponse withBeds(List<Bed> beds) {
+ setBeds(beds);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((beds == null) ? 0 : beds.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof BedsResponse)) {
+ return false;
+ }
+ BedsResponse other = (BedsResponse) obj;
+ if (beds == null) {
+ if (other.beds != null) {
+ return false;
+ }
+ } else if (!beds.equals(other.beds)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("BedsResponse [beds=");
+ builder.append(beds);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link Error} holds the Error response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class Error {
+ @SerializedName("Code")
+ private Long code;
+ @SerializedName("Message")
+ private String message;
+
+ public Long getCode() {
+ return code;
+ }
+
+ public void setCode(Long code) {
+ this.code = code;
+ }
+
+ public Error withCode(Long code) {
+ setCode(code);
+ return this;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Error withMessage(String message) {
+ setMessage(message);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((code == null) ? 0 : code.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Error)) {
+ return false;
+ }
+ Error other = (Error) obj;
+ if (code == null) {
+ if (other.code != null) {
+ return false;
+ }
+ } else if (!code.equals(other.code)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Error [code=");
+ builder.append(code);
+ builder.append(", message=");
+ builder.append(message);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link Failure} holds the Failure response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class Failure {
+ @SerializedName("Error")
+ private Error error;
+
+ public Error getError() {
+ return error;
+ }
+
+ public void setError(Error error) {
+ this.error = error;
+ }
+
+ public Failure withError(Error error) {
+ setError(error);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((error == null) ? 0 : error.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Failure)) {
+ return false;
+ }
+ Failure other = (Failure) obj;
+ if (error == null) {
+ if (other.error != null) {
+ return false;
+ }
+ } else if (!error.equals(other.error)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Failure [error=");
+ builder.append(error);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import java.util.List;
+
+/**
+ * The {@link FamilyStatusResponse} holds the FamilyStatusResponse response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class FamilyStatusResponse {
+ private List<BedStatus> beds;
+
+ public List<BedStatus> getBeds() {
+ return beds;
+ }
+
+ public void setBeds(List<BedStatus> beds) {
+ this.beds = beds;
+ }
+
+ public FamilyStatusResponse withBeds(List<BedStatus> beds) {
+ setBeds(beds);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((beds == null) ? 0 : beds.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof FamilyStatusResponse)) {
+ return false;
+ }
+ FamilyStatusResponse other = (FamilyStatusResponse) obj;
+ if (beds == null) {
+ if (other.beds != null) {
+ return false;
+ }
+ } else if (!beds.equals(other.beds)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("FamilyStatus [beds=");
+ builder.append(beds);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+/**
+ * The {@link LoginInfo} holds the LoginInfo response from the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class LoginInfo {
+ private String userId;
+ private String key;
+ private Long registrationState;
+ private Long edpLoginStatus;
+ private String edpLoginMessage;
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public LoginInfo withUserId(String userId) {
+ setUserId(userId);
+ return this;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public LoginInfo withKey(String key) {
+ setKey(key);
+ return this;
+ }
+
+ public Long getRegistrationState() {
+ return registrationState;
+ }
+
+ public void setRegistrationState(Long registrationState) {
+ this.registrationState = registrationState;
+ }
+
+ public LoginInfo withRegistrationState(Long registrationState) {
+ setRegistrationState(registrationState);
+ return this;
+ }
+
+ public Long getEdpLoginStatus() {
+ return edpLoginStatus;
+ }
+
+ public void setEdpLoginStatus(Long edpLoginStatus) {
+ this.edpLoginStatus = edpLoginStatus;
+ }
+
+ public LoginInfo withEdpLoginStatus(Long edpLoginStatus) {
+ setEdpLoginStatus(edpLoginStatus);
+ return this;
+ }
+
+ public String getEdpLoginMessage() {
+ return edpLoginMessage;
+ }
+
+ public void setEdpLoginMessage(String edpLoginMessage) {
+ this.edpLoginMessage = edpLoginMessage;
+ }
+
+ public LoginInfo withEdpLoginMessage(String edpLoginMessage) {
+ setEdpLoginMessage(edpLoginMessage);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ result = prime * result + (int) (registrationState ^ (registrationState >>> 32));
+ result = prime * result + ((userId == null) ? 0 : userId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof LoginInfo)) {
+ return false;
+ }
+ LoginInfo other = (LoginInfo) obj;
+ if (key == null) {
+ if (other.key != null) {
+ return false;
+ }
+ } else if (!key.equals(other.key)) {
+ return false;
+ }
+ if (!registrationState.equals(other.registrationState)) {
+ return false;
+ }
+ if (userId == null) {
+ if (other.userId != null) {
+ return false;
+ }
+ } else if (!userId.equals(other.userId)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("LoginInfo [userId=");
+ builder.append(userId);
+ builder.append(", key=");
+ builder.append(key);
+ builder.append(", registrationState=");
+ builder.append(registrationState);
+ builder.append(", edpLoginStatus=");
+ builder.append(edpLoginStatus);
+ builder.append(", edpLoginMessage=");
+ builder.append(edpLoginMessage);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+/**
+ * The {@link LoginRequest} holds the Login request sent to the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class LoginRequest {
+ private String login;
+ private String password;
+
+ public String getLogin() {
+ return login;
+ }
+
+ public void setLogin(String login) {
+ this.login = login;
+ }
+
+ public LoginRequest withLogin(String login) {
+ setLogin(login);
+ return this;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public LoginRequest withPassword(String password) {
+ setPassword(password);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((login == null) ? 0 : login.hashCode());
+ result = prime * result + ((password == null) ? 0 : password.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof LoginRequest)) {
+ return false;
+ }
+ LoginRequest other = (LoginRequest) obj;
+ if (login == null) {
+ if (other.login != null) {
+ return false;
+ }
+ } else if (!login.equals(other.login)) {
+ return false;
+ }
+ if (password == null) {
+ if (other.password != null) {
+ return false;
+ }
+ } else if (!password.equals(other.password)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("LoginRequest [login=");
+ builder.append(login);
+ builder.append(", password=");
+ builder.append(password);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+/**
+ * The {@link PauseModeRequest} holds the request to pause the bed data collection.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+public class PauseModeRequest {
+ private String mode;
+
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public PauseModeRequest withMode(String mode) {
+ setMode(mode);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mode == null) ? 0 : mode.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof PauseModeRequest)) {
+ return false;
+ }
+ PauseModeRequest other = (PauseModeRequest) obj;
+ if (mode == null) {
+ if (other.mode != null) {
+ return false;
+ }
+ } else if (!mode.equals(other.mode)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("SleepNumberRequest [mode=");
+ builder.append(mode);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+/**
+ * The {@link PauseModeResponse} holds the response to the request to pause the bed data collection.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+public class PauseModeResponse {
+ private String accountId;
+ private String bedId;
+ private String pauseMode;
+
+ public String getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(String accountId) {
+ this.accountId = accountId;
+ }
+
+ public PauseModeResponse withAccountId(String accountId) {
+ setAccountId(accountId);
+ return this;
+ }
+
+ public String getBedId() {
+ return bedId;
+ }
+
+ public void setBedId(String bedId) {
+ this.bedId = bedId;
+ }
+
+ public PauseModeResponse withBedId(String bedId) {
+ setBedId(bedId);
+ return this;
+ }
+
+ public String getPauseMode() {
+ return pauseMode;
+ }
+
+ public void setPauseMode(String pauseMode) {
+ this.pauseMode = pauseMode;
+ }
+
+ public PauseModeResponse withPauseMode(String pauseMode) {
+ setPauseMode(pauseMode);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((accountId == null) ? 0 : accountId.hashCode());
+ result = prime * result + ((bedId == null) ? 0 : bedId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof PauseModeResponse)) {
+ return false;
+ }
+ PauseModeResponse other = (PauseModeResponse) obj;
+ if (accountId == null) {
+ if (other.accountId != null) {
+ return false;
+ }
+ } else if (!accountId.equals(other.accountId)) {
+ return false;
+ }
+ if (bedId == null) {
+ if (other.bedId != null) {
+ return false;
+ }
+ } else if (!bedId.equals(other.bedId)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PauseMode [accountId=");
+ builder.append(accountId);
+ builder.append(", bedId=");
+ builder.append(bedId);
+ builder.append(", pauseMode=");
+ builder.append(pauseMode);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link SleepDataDay} holds the information for a daily sleep session.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+public class SleepDataDay {
+
+ @SerializedName("date")
+ private LocalDate date;
+
+ @SerializedName("message")
+ private String dailyMessage;
+
+ @SerializedName("sessions")
+ private List<SleepDataSession> dailySessions;
+
+ public LocalDate getDate() {
+ return date;
+ }
+
+ public String getMessage() {
+ return dailyMessage;
+ }
+
+ public List<SleepDataSession> getDailySessions() {
+ return dailySessions;
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import java.util.List;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link SleepDataResponse} holds the response to a request for sleep data.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+public class SleepDataResponse {
+ @SerializedName("sleeperId")
+ private String sleeperId;
+
+ @SerializedName("avgSleepIQ")
+ private Integer averageSleepIQ;
+
+ @SerializedName("avgHeartRate")
+ private Integer averageHeartRate;
+
+ @SerializedName("avgRespirationRate")
+ private Integer averageResperationRate;
+
+ @SerializedName("inBed")
+ private Integer totalInBedSeconds;
+
+ @SerializedName("outOfBed")
+ private Integer totalOutOfBedSeconds;
+
+ @SerializedName("restful")
+ private Integer totalRestfulSeconds;
+
+ @SerializedName("restless")
+ private Integer totalRestlessSeconds;
+
+ @SerializedName("sleepData")
+ private List<SleepDataDay> sleepDataDays;
+
+ public String getSleeperId() {
+ return sleeperId;
+ }
+
+ public Integer getAverageSleepIQ() {
+ return averageSleepIQ;
+ }
+
+ public Integer getAverageHeartRate() {
+ return averageHeartRate;
+ }
+
+ public Integer getAverageRespirationRate() {
+ return averageResperationRate;
+ }
+
+ public Integer getTotalSleepSessionTime() {
+ return totalInBedSeconds + totalOutOfBedSeconds;
+ }
+
+ public Integer getTotalInBedSeconds() {
+ return totalInBedSeconds;
+ }
+
+ public Integer getTotalOutOfBedSeconds() {
+ return totalOutOfBedSeconds;
+ }
+
+ public Integer getTotalRestfulSeconds() {
+ return totalRestfulSeconds;
+ }
+
+ public Integer getTotalRestlessSeconds() {
+ return totalRestlessSeconds;
+ }
+
+ public List<SleepDataDay> getSleepDataDays() {
+ return sleepDataDays;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("SleepDataResponse [sleepData=");
+ builder.append("averageSleepIQ=");
+ builder.append(averageSleepIQ);
+ builder.append(", averageHeartRate=");
+ builder.append(averageHeartRate);
+ builder.append(", averageResperationRate=");
+ builder.append(averageResperationRate);
+ builder.append(", totalInBedSeconds=");
+ builder.append(totalInBedSeconds);
+ builder.append(", totalOutOfBedSeconds=");
+ builder.append(totalOutOfBedSeconds);
+ builder.append(", totalRestfulSeconds=");
+ builder.append(totalRestfulSeconds);
+ builder.append(", totalRestlessSeconds=");
+ builder.append(totalRestlessSeconds);
+ builder.append(", totalSleepSessionTime=");
+ builder.append(getTotalSleepSessionTime());
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link SleepDataSession} holds the data for a sleep session.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+public class SleepDataSession {
+
+ @SerializedName("avgSleepIQ")
+ private Integer sessionAverageSleepIQ;
+
+ @SerializedName("avgHeartRate")
+ private Integer sessionAverageHeartRate;
+
+ @SerializedName("avgRespirationRate")
+ private Integer sessionAverageRespirationRate;
+
+ @SerializedName("isFinalized")
+ private boolean sessionIsFinalized;
+
+ @SerializedName("totalSleepSessionTime")
+ private Integer sessionTotalSeconds;
+
+ @SerializedName("inBed")
+ private Integer sessionInBedSeconds;
+
+ @SerializedName("outOfBed")
+ private Integer sessionOutOfBedSeconds;
+
+ @SerializedName("restful")
+ private Integer sessionRestfulSeconds;
+
+ @SerializedName("restless")
+ private Integer sessionRestlessSeconds;
+
+ public Integer getSessionAverageSleepIQ() {
+ return sessionAverageSleepIQ;
+ }
+
+ public Integer getSessionAverageHeartRate() {
+ return sessionAverageHeartRate;
+ }
+
+ public Integer getSessionAverageRespirationRate() {
+ return sessionAverageRespirationRate;
+ }
+
+ public Boolean sessionIsFinalized() {
+ return sessionIsFinalized;
+ }
+
+ public Integer getSessionTotalSeconds() {
+ return sessionTotalSeconds;
+ }
+
+ public Integer getSessionInBedSeconds() {
+ return sessionInBedSeconds;
+ }
+
+ public Integer getSessionOutOfBedSeconds() {
+ return sessionOutOfBedSeconds;
+ }
+
+ public Integer getSessionRestfulSeconds() {
+ return sessionRestfulSeconds;
+ }
+
+ public Integer getSessionRestlessSeconds() {
+ return sessionRestlessSeconds;
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+
+/**
+ * The {@link SleepNumberRequest} holds the information used to set the sleep number
+ * for a bed side.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class SleepNumberRequest {
+ private String bedId;
+ private Integer sleepNumber;
+ private Side side;
+
+ public String getBedId() {
+ return bedId;
+ }
+
+ public void setBedId(String bedId) {
+ this.bedId = bedId;
+ }
+
+ public SleepNumberRequest withBedId(String bedId) {
+ setBedId(bedId);
+ return this;
+ }
+
+ public Integer getSleepNumber() {
+ return sleepNumber;
+ }
+
+ public void setSleepNumber(Integer sleepNumber) {
+ this.sleepNumber = sleepNumber;
+ }
+
+ public SleepNumberRequest withSleepNumber(Integer sleepNumber) {
+ setSleepNumber(sleepNumber);
+ return this;
+ }
+
+ public Side getSide() {
+ return side;
+ }
+
+ public void setSide(Side side) {
+ this.side = side;
+ }
+
+ public SleepNumberRequest withSide(Side side) {
+ setSide(side);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((bedId == null) ? 0 : bedId.hashCode());
+ result = prime * result + ((sleepNumber == null) ? 0 : sleepNumber.hashCode());
+ result = prime * result + ((side == null) ? 0 : side.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof SleepNumberRequest)) {
+ return false;
+ }
+ SleepNumberRequest other = (SleepNumberRequest) obj;
+ if (bedId == null) {
+ if (other.bedId != null) {
+ return false;
+ }
+ } else if (!bedId.equals(other.bedId)) {
+ return false;
+ }
+ if (sleepNumber == null) {
+ if (other.sleepNumber != null) {
+ return false;
+ }
+ } else if (sleepNumber.equals(other.sleepNumber)) {
+ return false;
+ }
+ if (side == null) {
+ if (other.side != null) {
+ return false;
+ }
+ } else if (!side.equals(other.side)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("SleepNumberRequest [bedId=");
+ builder.append(bedId);
+ builder.append(", sleepNumber=");
+ builder.append(sleepNumber);
+ builder.append(", side=");
+ builder.append(side);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The {@link Sleeper} holds the information about the sleeper that's
+ * associated with a bed side.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class Sleeper {
+ private String firstName;
+ private Boolean active;
+ private Boolean emailValidated;
+ @SerializedName("isChild")
+ private Boolean child;
+ private String bedId;
+ private String birthYear;
+ private String zipCode;
+ private String timezone;
+ @SerializedName("isMale")
+ private Boolean male;
+ private Integer weight; // lbs
+ private String duration;
+ private String sleeperId;
+ private Integer height; // inches
+ private Long licenseVersion;
+ private String username;
+ private Integer birthMonth; // 0-based; 12 means not entered?
+ private Integer sleepGoal;
+ @SerializedName("isAccountOwner")
+ private Boolean accountOwner;
+ private String accountId;
+ private String email;
+ private String avatar;
+ private String lastLogin; // should be ZonedDateTime but provider passes string "null" when missing
+ private Side side; // 0=left; 1=right
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public Sleeper withFirstName(String firstName) {
+ setFirstName(firstName);
+ return this;
+ }
+
+ public Boolean isActive() {
+ return active;
+ }
+
+ public void setActive(Boolean active) {
+ this.active = active;
+ }
+
+ public Sleeper withActive(Boolean active) {
+ setActive(active);
+ return this;
+ }
+
+ public Boolean isEmailValidated() {
+ return emailValidated;
+ }
+
+ public void setEmailValidated(Boolean emailValidated) {
+ this.emailValidated = emailValidated;
+ }
+
+ public Sleeper withEmailValidated(Boolean emailValidated) {
+ setEmailValidated(emailValidated);
+ return this;
+ }
+
+ public Boolean isChild() {
+ return child;
+ }
+
+ public void setChild(Boolean child) {
+ this.child = child;
+ }
+
+ public Sleeper withChild(Boolean child) {
+ setChild(child);
+ return this;
+ }
+
+ public String getBedId() {
+ return bedId;
+ }
+
+ public void setBedId(String bedId) {
+ this.bedId = bedId;
+ }
+
+ public Sleeper withBedId(String bedId) {
+ setBedId(bedId);
+ return this;
+ }
+
+ public String getBirthYear() {
+ return birthYear;
+ }
+
+ public void setBirthYear(String birthYear) {
+ this.birthYear = birthYear;
+ }
+
+ public Sleeper withBirthYear(String birthYear) {
+ setBirthYear(birthYear);
+ return this;
+ }
+
+ public String getZipCode() {
+ return zipCode;
+ }
+
+ public void setZipCode(String zipCode) {
+ this.zipCode = zipCode;
+ }
+
+ public Sleeper withZipCode(String zipCode) {
+ setZipCode(zipCode);
+ return this;
+ }
+
+ public String getTimezone() {
+ return timezone;
+ }
+
+ public void setTimezone(String timezone) {
+ this.timezone = timezone;
+ }
+
+ public Sleeper withTimezone(String timezone) {
+ setTimezone(timezone);
+ return this;
+ }
+
+ public Boolean isMale() {
+ return male;
+ }
+
+ public void setMale(Boolean male) {
+ this.male = male;
+ }
+
+ public Sleeper withMale(Boolean male) {
+ setMale(male);
+ return this;
+ }
+
+ public Integer getWeight() {
+ return weight;
+ }
+
+ public void setWeight(Integer weight) {
+ this.weight = weight;
+ }
+
+ public Sleeper withWeight(Integer weight) {
+ setWeight(weight);
+ return this;
+ }
+
+ public String getDuration() {
+ return duration;
+ }
+
+ public void setDuration(String duration) {
+ this.duration = duration;
+ }
+
+ public Sleeper withDuration(String duration) {
+ setDuration(duration);
+ return this;
+ }
+
+ public String getSleeperId() {
+ return sleeperId;
+ }
+
+ public void setSleeperId(String sleeperId) {
+ this.sleeperId = sleeperId;
+ }
+
+ public Sleeper withSleeperId(String sleeperId) {
+ setSleeperId(sleeperId);
+ return this;
+ }
+
+ public Integer getHeight() {
+ return height;
+ }
+
+ public void setHeight(Integer height) {
+ this.height = height;
+ }
+
+ public Sleeper withHeight(Integer height) {
+ setHeight(height);
+ return this;
+ }
+
+ public Long getLicenseVersion() {
+ return licenseVersion;
+ }
+
+ public void setLicenseVersion(Long licenseVersion) {
+ this.licenseVersion = licenseVersion;
+ }
+
+ public Sleeper withLicenseVersion(Long licenseVersion) {
+ setLicenseVersion(licenseVersion);
+ return this;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public Sleeper withUsername(String username) {
+ setUsername(username);
+ return this;
+ }
+
+ public Integer getBirthMonth() {
+ return birthMonth;
+ }
+
+ public void setBirthMonth(Integer birthMonth) {
+ this.birthMonth = birthMonth;
+ }
+
+ public Sleeper withBirthMonth(Integer birthMonth) {
+ setBirthMonth(birthMonth);
+ return this;
+ }
+
+ public Integer getSleepGoal() {
+ return sleepGoal;
+ }
+
+ public void setSleepGoal(Integer sleepGoal) {
+ this.sleepGoal = sleepGoal;
+ }
+
+ public Sleeper withSleepGoal(Integer sleepGoal) {
+ setSleepGoal(sleepGoal);
+ return this;
+ }
+
+ public Boolean isAccountOwner() {
+ return accountOwner;
+ }
+
+ public void setAccountOwner(Boolean accountOwner) {
+ this.accountOwner = accountOwner;
+ }
+
+ public Sleeper withAccountOwner(Boolean accountOwner) {
+ setAccountOwner(accountOwner);
+ return this;
+ }
+
+ public String getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(String accountId) {
+ this.accountId = accountId;
+ }
+
+ public Sleeper withAccountId(String accountId) {
+ setAccountId(accountId);
+ return this;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public Sleeper withEmail(String email) {
+ setEmail(email);
+ return this;
+ }
+
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public Sleeper withAvatar(String avatar) {
+ setAvatar(avatar);
+ return this;
+ }
+
+ public String getLastLogin() {
+ return lastLogin;
+ }
+
+ public void setLastLogin(String lastLogin) {
+ this.lastLogin = lastLogin;
+ }
+
+ public Sleeper withLastLogin(String lastLogin) {
+ setLastLogin(lastLogin);
+ return this;
+ }
+
+ public Side getSide() {
+ return side;
+ }
+
+ public void setSide(Side side) {
+ this.side = side;
+ }
+
+ public Sleeper withSide(Side side) {
+ setSide(side);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((sleeperId == null) ? 0 : sleeperId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Sleeper)) {
+ return false;
+ }
+ Sleeper other = (Sleeper) obj;
+ if (sleeperId == null) {
+ if (other.sleeperId != null) {
+ return false;
+ }
+ } else if (!sleeperId.equals(other.sleeperId)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Sleeper [firstName=");
+ builder.append(firstName);
+ builder.append(", active=");
+ builder.append(active);
+ builder.append(", emailValidated=");
+ builder.append(emailValidated);
+ builder.append(", child=");
+ builder.append(child);
+ builder.append(", bedId=");
+ builder.append(bedId);
+ builder.append(", birthYear=");
+ builder.append(birthYear);
+ builder.append(", zipCode=");
+ builder.append(zipCode);
+ builder.append(", timezone=");
+ builder.append(timezone);
+ builder.append(", male=");
+ builder.append(male);
+ builder.append(", weight=");
+ builder.append(weight);
+ builder.append(", duration=");
+ builder.append(duration);
+ builder.append(", sleeperId=");
+ builder.append(sleeperId);
+ builder.append(", height=");
+ builder.append(height);
+ builder.append(", licenseVersion=");
+ builder.append(licenseVersion);
+ builder.append(", username=");
+ builder.append(username);
+ builder.append(", birthMonth=");
+ builder.append(birthMonth);
+ builder.append(", sleepGoal=");
+ builder.append(sleepGoal);
+ builder.append(", accountOwner=");
+ builder.append(accountOwner);
+ builder.append(", accountId=");
+ builder.append(accountId);
+ builder.append(", email=");
+ builder.append(email);
+ builder.append(", avatar=");
+ builder.append(avatar);
+ builder.append(", lastLogin=");
+ builder.append(lastLogin);
+ builder.append(", side=");
+ builder.append(side);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import java.util.List;
+
+/**
+ * The {@link SleeperResponse} holds the information about the sleepers assigned to the bed sides.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class SleepersResponse {
+ private List<Sleeper> sleepers;
+
+ public List<Sleeper> getSleepers() {
+ return sleepers;
+ }
+
+ public void setSleepers(List<Sleeper> sleepers) {
+ this.sleepers = sleepers;
+ }
+
+ public SleepersResponse withSleepers(List<Sleeper> sleepers) {
+ setSleepers(sleepers);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((sleepers == null) ? 0 : sleepers.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof SleepersResponse)) {
+ return false;
+ }
+ SleepersResponse other = (SleepersResponse) obj;
+ if (sleepers == null) {
+ if (other.sleepers != null) {
+ return false;
+ }
+ } else if (!sleepers.equals(other.sleepers)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("SleepersResponse [sleepers=");
+ builder.append(sleepers);
+ builder.append("]");
+ return builder.toString();
+ }
+}
--- /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.sleepiq.internal.api.dto;
+
+import java.time.Duration;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The {@link TimeSince} converts from "nn d hh:mm:ss" to Duration
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+public class TimeSince {
+ private static final Pattern PATTERN = Pattern.compile("(([0-9]+) d )?([0-9]{2}):([0-9]{2}):([0-9]{2})",
+ Pattern.CASE_INSENSITIVE);
+
+ private Duration duration;
+
+ public Duration getDuration() {
+ return duration;
+ }
+
+ public void setDuration(Duration duration) {
+ this.duration = duration == null ? null : duration.abs();
+ }
+
+ public TimeSince withDuration(long days, long hours, long minutes, long seconds) {
+ return withDuration(Duration.ofSeconds(TimeUnit.DAYS.toSeconds(days) + TimeUnit.HOURS.toSeconds(hours)
+ + TimeUnit.MINUTES.toSeconds(minutes) + seconds));
+ }
+
+ public TimeSince withDuration(Duration duration) {
+ setDuration(duration);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((duration == null) ? 0 : duration.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof TimeSince)) {
+ return false;
+ }
+ TimeSince other = (TimeSince) obj;
+ if (duration == null) {
+ if (other.duration != null) {
+ return false;
+ }
+ } else if (!duration.equals(other.duration)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ long totalDays = duration.toDays();
+ long totalHours = duration.toHours();
+ long totalMinutes = duration.toMinutes();
+ long totalSeconds = duration.getSeconds();
+
+ long hours = totalHours - TimeUnit.DAYS.toHours(totalDays);
+ long minutes = totalMinutes - TimeUnit.HOURS.toMinutes(totalHours);
+ long seconds = totalSeconds - TimeUnit.MINUTES.toSeconds(totalMinutes);
+
+ if (totalDays > 0) {
+ return String.format("%d d %02d:%02d:%02d", totalDays, hours, minutes, seconds);
+ }
+
+ return String.format("%02d:%02d:%02d", hours, minutes, seconds);
+ }
+
+ public static TimeSince parse(CharSequence text) {
+ Objects.requireNonNull(text, "text");
+
+ Matcher matcher = PATTERN.matcher(text);
+ if (!matcher.matches()) {
+ return new TimeSince().withDuration(Duration.ZERO);
+ }
+
+ String dayMatch = matcher.group(2);
+ String hourMatch = matcher.group(3);
+ String minuteMatch = matcher.group(4);
+ String secondMatch = matcher.group(5);
+
+ StringBuilder sb = new StringBuilder("P");
+ if (dayMatch != null) {
+ sb.append(dayMatch).append('D');
+ }
+ sb.append('T').append(hourMatch).append('H').append(minuteMatch).append('M').append(secondMatch).append('S');
+
+ return new TimeSince().withDuration(Duration.parse(sb.toString()));
+ }
+}
--- /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.sleepiq.internal.api.enums;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link Side} represents the possible sides of the bed (i.e. left and right).
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public enum Side {
+ LEFT(0),
+ RIGHT(1);
+
+ private final int side;
+
+ Side(final int side) {
+ this.side = side;
+ }
+
+ public int value() {
+ return side;
+ }
+
+ public static Side forValue(int value) {
+ for (Side s : Side.values()) {
+ if (s.side == value) {
+ return s;
+ }
+ }
+ throw new IllegalArgumentException("Invalid side: " + value);
+ }
+
+ public static Side convertFromGroup(@Nullable String channelGroup) {
+ return "left".equalsIgnoreCase(channelGroup) ? Side.LEFT : Side.RIGHT;
+ }
+
+ @Override
+ public String toString() {
+ return side == 0 ? LEFT.name() : RIGHT.name();
+ }
+}
--- /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.sleepiq.internal.api.enums;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link SleepDataInterval} represents the time periods that can be
+ * used for sleep data requests.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public enum SleepDataInterval {
+ DAY("D1"),
+ WEEK("W1"),
+ MONTH("M1");
+
+ private final String interval;
+
+ SleepDataInterval(final String interval) {
+ this.interval = interval;
+ }
+
+ public String value() {
+ return interval;
+ }
+
+ public static SleepDataInterval forValue(String value) {
+ for (SleepDataInterval s : SleepDataInterval.values()) {
+ if (s.interval.equals(value)) {
+ return s;
+ }
+ }
+ throw new IllegalArgumentException("Invalid sleep data interval: " + value);
+ }
+
+ @Override
+ public String toString() {
+ return interval;
+ }
+}
--- /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.sleepiq.internal.api.impl;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link Endpoints} class contains all endpoints for the sleepiq API.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class Endpoints {
+ private static final String LOGIN = "/rest/login";
+ private static final String BED = "/rest/bed";
+ private static final String SLEEPER = "/rest/sleeper";
+ private static final String FAMILY_STATUS = "/rest/bed/familyStatus";
+ private static final String PAUSE_MODE = "/rest/bed/%s/pauseMode";
+ private static final String SLEEP_DATA = "/rest/sleepData";
+ private static final String SET_SLEEP_NUMBER = "/rest/bed/%s/sleepNumber";
+ private static final String SET_PAUSE_MODE = "/rest/bed/%s/pauseMode";
+
+ public static String login() {
+ return LOGIN;
+ }
+
+ public static String bed() {
+ return BED;
+ }
+
+ public static String sleeper() {
+ return SLEEPER;
+ }
+
+ public static String familyStatus() {
+ return FAMILY_STATUS;
+ }
+
+ public static String pauseMode(String bedId) {
+ return String.format(PAUSE_MODE, bedId);
+ }
+
+ public static String sleepData() {
+ return SLEEP_DATA;
+ }
+
+ public static String setSleepNumber(String bedId) {
+ return String.format(SET_SLEEP_NUMBER, bedId);
+ }
+
+ public static String setPauseMode(String bedId) {
+ return String.format(SET_PAUSE_MODE, bedId);
+ }
+
+ private Endpoints() {
+ }
+}
--- /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.sleepiq.internal.api.impl;
+
+import java.time.ZonedDateTime;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepNumberRequest;
+import org.openhab.binding.sleepiq.internal.api.dto.TimeSince;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+import org.openhab.binding.sleepiq.internal.api.impl.typeadapters.SideTypeAdapter;
+import org.openhab.binding.sleepiq.internal.api.impl.typeadapters.SleepNumberRequestAdapter;
+import org.openhab.binding.sleepiq.internal.api.impl.typeadapters.TimeSinceTypeAdapter;
+import org.openhab.binding.sleepiq.internal.api.impl.typeadapters.ZonedDateTimeTypeAdapter;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * The {@link GsonGenerator} class creates the GSON generator object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class GsonGenerator {
+ public static Gson create() {
+ return create(false);
+ }
+
+ public static Gson create(boolean prettyPrint) {
+ GsonBuilder builder = new GsonBuilder();
+ builder.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeTypeAdapter());
+ builder.registerTypeAdapter(TimeSince.class, new TimeSinceTypeAdapter());
+ builder.registerTypeAdapter(SleepNumberRequest.class, new SleepNumberRequestAdapter());
+ builder.registerTypeAdapter(Side.class, new SideTypeAdapter());
+
+ if (prettyPrint) {
+ builder.setPrettyPrinting();
+ }
+ return builder.create();
+ }
+
+ private GsonGenerator() {
+ }
+}
--- /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.sleepiq.internal.api.impl;
+
+import java.net.CookieStore;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.openhab.binding.sleepiq.internal.api.CommunicationException;
+import org.openhab.binding.sleepiq.internal.api.Configuration;
+import org.openhab.binding.sleepiq.internal.api.LoginException;
+import org.openhab.binding.sleepiq.internal.api.ResponseFormatException;
+import org.openhab.binding.sleepiq.internal.api.SleepIQ;
+import org.openhab.binding.sleepiq.internal.api.UnauthorizedException;
+import org.openhab.binding.sleepiq.internal.api.dto.Bed;
+import org.openhab.binding.sleepiq.internal.api.dto.BedsResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.Failure;
+import org.openhab.binding.sleepiq.internal.api.dto.FamilyStatusResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.LoginInfo;
+import org.openhab.binding.sleepiq.internal.api.dto.LoginRequest;
+import org.openhab.binding.sleepiq.internal.api.dto.PauseModeResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepDataResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepNumberRequest;
+import org.openhab.binding.sleepiq.internal.api.dto.Sleeper;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepersResponse;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+import org.openhab.binding.sleepiq.internal.api.enums.SleepDataInterval;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * The {@link SleepIQImpl} class handles all interactions with the sleepiq service.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class SleepIQImpl implements SleepIQ {
+ private static final String PARAM_KEY = "_k";
+ private static final String USER_AGENT = "SleepIQ/1593766370 CFNetwork/1185.2 Darwin/20.0.0";
+
+ private static final Gson GSON = GsonGenerator.create(false);
+
+ private final Logger logger = LoggerFactory.getLogger(SleepIQImpl.class);
+
+ private final HttpClient httpClient;
+ private final CookieStore cookieStore;
+
+ protected final Configuration config;
+
+ private final LoginRequest loginRequest = new LoginRequest();
+ private volatile @Nullable LoginInfo loginInfo;
+
+ public SleepIQImpl(Configuration config, HttpClient httpClient) {
+ this.config = config;
+ this.httpClient = httpClient;
+ cookieStore = httpClient.getCookieStore();
+ loginRequest.setLogin(config.getUsername());
+ loginRequest.setPassword(config.getPassword());
+ }
+
+ @Override
+ public void shutdown() {
+ cookieStore.removeAll();
+ }
+
+ @Override
+ public @Nullable LoginInfo login() throws LoginException, UnauthorizedException {
+ logger.trace("SleepIQ: login: loginInfo={}", loginInfo);
+ if (loginInfo == null) {
+ synchronized (this) {
+ if (loginInfo == null) {
+ Request request = httpClient.newRequest(config.getBaseUri()).path(Endpoints.login())
+ .agent(USER_AGENT).header(HttpHeader.CONTENT_TYPE, "application/json")
+ .timeout(10, TimeUnit.SECONDS).method(HttpMethod.PUT)
+ .content(new StringContentProvider(GSON.toJson(loginRequest)), "application/json");
+ logger.trace("SleepIQ: login: request url={}", request.getURI());
+
+ try {
+ ContentResponse response = request.send();
+ logger.debug("SleepIQ: login: status={}, content={}", response.getStatus(),
+ response.getContentAsString());
+ if (isUnauthorized(response)) {
+ Failure failure = GSON.fromJson(response.getContentAsString(), Failure.class);
+ String message = failure != null ? failure.getError().getMessage() : "Login unauthorized";
+ throw new UnauthorizedException(message);
+ }
+ if (isNotOk(response)) {
+ Failure failure = GSON.fromJson(response.getContentAsString(), Failure.class);
+ String message = failure != null ? failure.getError().getMessage() : "Login failed";
+ throw new LoginException(message);
+ }
+ try {
+ loginInfo = GSON.fromJson(response.getContentAsString(), LoginInfo.class);
+ } catch (JsonSyntaxException e) {
+ throw new LoginException("Failed to parse 'login' response");
+ }
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
+ logger.info("SleepIQ: login: Login failed message={}", e.getMessage(), e);
+ throw new LoginException("Problem communicating with SleepIQ cloud service");
+ }
+ }
+ }
+ }
+ return loginInfo;
+ }
+
+ @Override
+ public List<Bed> getBeds() throws LoginException, CommunicationException, ResponseFormatException {
+ try {
+ String contentResponse = cloudRequest(Endpoints.bed());
+ BedsResponse response = GSON.fromJson(contentResponse, BedsResponse.class);
+ if (response != null) {
+ return response.getBeds();
+ } else {
+ throw new ResponseFormatException("Failed to get a valid 'beds' response from cloud");
+ }
+ } catch (JsonSyntaxException e) {
+ throw new ResponseFormatException("Failed to parse 'beds' response");
+ }
+ }
+
+ @Override
+ public FamilyStatusResponse getFamilyStatus()
+ throws LoginException, ResponseFormatException, CommunicationException {
+ try {
+ String contentResponse = cloudRequest(Endpoints.familyStatus());
+ FamilyStatusResponse response = GSON.fromJson(contentResponse, FamilyStatusResponse.class);
+ if (response != null) {
+ return response;
+ } else {
+ throw new ResponseFormatException("Failed to get a valid 'familyStatus' response from cloud");
+ }
+ } catch (JsonSyntaxException e) {
+ throw new ResponseFormatException("Failed to parse 'familyStatus' response");
+ }
+ }
+
+ @Override
+ public List<Sleeper> getSleepers() throws LoginException, ResponseFormatException, CommunicationException {
+ try {
+ String contentResponse = cloudRequest(Endpoints.sleeper());
+ SleepersResponse response = GSON.fromJson(contentResponse, SleepersResponse.class);
+ if (response != null) {
+ return response.getSleepers();
+ } else {
+ throw new ResponseFormatException("Failed to get a valid 'sleepers' response from cloud");
+ }
+ } catch (JsonSyntaxException e) {
+ throw new ResponseFormatException("Failed to parse 'sleepers' response");
+ }
+ }
+
+ @Override
+ public PauseModeResponse getPauseMode(String bedId)
+ throws LoginException, ResponseFormatException, CommunicationException {
+ try {
+ String contentResponse = cloudRequest(Endpoints.pauseMode(bedId));
+ PauseModeResponse response = GSON.fromJson(contentResponse, PauseModeResponse.class);
+ if (response != null) {
+ return response;
+ } else {
+ throw new ResponseFormatException("Failed to get a valid 'pauseMode' response from cloud");
+ }
+ } catch (JsonSyntaxException e) {
+ throw new ResponseFormatException("Failed to parse 'pauseMode' response");
+ }
+ }
+
+ @Override
+ public SleepDataResponse getSleepData(String sleeperId, SleepDataInterval interval)
+ throws LoginException, ResponseFormatException, CommunicationException {
+ try {
+ Map<String, String> parameters = new HashMap<>();
+ parameters.put("interval", interval.value());
+ parameters.put("sleeper", sleeperId);
+ parameters.put("includeSlices", "false");
+ parameters.put("date", formatSleepDataDate(ZonedDateTime.now()));
+ String contentResponse = cloudRequest(Endpoints.sleepData(), parameters);
+ SleepDataResponse response = GSON.fromJson(contentResponse, SleepDataResponse.class);
+ if (response != null) {
+ return response;
+ } else {
+ throw new ResponseFormatException("Failed to get a valid 'sleepData' response from cloud");
+ }
+ } catch (JsonSyntaxException e) {
+ throw new ResponseFormatException("Failed to parse 'sleepData' response");
+ }
+ }
+
+ private String formatSleepDataDate(ZonedDateTime zonedDateTime) {
+ return DateTimeFormatter.ofPattern("yyyy-MM-dd").format(zonedDateTime);
+ }
+
+ @Override
+ public void setSleepNumber(String bedId, Side side, int sleepNumber)
+ throws LoginException, ResponseFormatException, CommunicationException {
+ String body = GSON.toJson(new SleepNumberRequest().withBedId(bedId).withSleepNumber(sleepNumber).withSide(side),
+ SleepNumberRequest.class);
+ logger.debug("SleepIQ: setSleepNumber: Request body={}", body);
+ cloudRequest(Endpoints.setSleepNumber(bedId), null, body);
+ }
+
+ @Override
+ public void setPauseMode(String bedId, boolean pauseMode)
+ throws LoginException, ResponseFormatException, CommunicationException {
+ logger.debug("SleepIQ: setPauseMode: command={}", pauseMode);
+ Map<String, String> requestParameters = new HashMap<>();
+ requestParameters.put("mode", pauseMode ? "on" : "off");
+ cloudRequest(Endpoints.setPauseMode(bedId), requestParameters, "");
+ }
+
+ private String cloudRequest(String endpoint)
+ throws LoginException, ResponseFormatException, CommunicationException {
+ return cloudRequest(endpoint, null, null);
+ }
+
+ private String cloudRequest(String endpoint, Map<String, String> parameters)
+ throws LoginException, ResponseFormatException, CommunicationException {
+ return cloudRequest(endpoint, parameters, null);
+ }
+
+ private String cloudRequest(String endpoint, @Nullable Map<String, String> parameters, @Nullable String body)
+ throws LoginException, ResponseFormatException, CommunicationException {
+ logger.debug("SleepIQ: cloudGetRequest: Invoke endpoint={}", endpoint);
+ ContentResponse response = (body == null ? doGet(endpoint, parameters) : doPut(endpoint, parameters, body));
+ if (isUnauthorized(response)) {
+ logger.debug("SleepIQ: cloudGetRequest: UNAUTHORIZED, reset login");
+ // Force new login and try again
+ resetLogin();
+ response = (body == null ? doGet(endpoint, parameters) : doPut(endpoint, parameters, body));
+ }
+ if (isNotOk(response)) {
+ throw new ResponseFormatException(String.format("Cloud API returned error: status=%d, message=%s",
+ response.getStatus(), HttpStatus.getCode(response.getStatus()).getMessage()));
+ }
+ return response.getContentAsString();
+ }
+
+ private ContentResponse doGet(String endpoint, @Nullable Map<String, String> parameters)
+ throws CommunicationException, LoginException {
+ LoginInfo login = login();
+ Request request = httpClient.newRequest(config.getBaseUri()).path(endpoint).param(PARAM_KEY, login.getKey())
+ .agent(USER_AGENT).header(HttpHeader.CONTENT_TYPE, "application/json").timeout(10, TimeUnit.SECONDS)
+ .method(HttpMethod.GET);
+ return doRequest(request, parameters);
+ }
+
+ private ContentResponse doPut(String endpoint, @Nullable Map<String, String> parameters, String body)
+ throws CommunicationException, LoginException {
+ LoginInfo login = login();
+ Request request = httpClient.newRequest(config.getBaseUri()).path(endpoint).param(PARAM_KEY, login.getKey())
+ .agent(USER_AGENT).header(HttpHeader.CONTENT_TYPE, "application/json").timeout(10, TimeUnit.SECONDS)
+ .method(HttpMethod.PUT).content(new StringContentProvider(body), "application/json");
+ return doRequest(request, parameters);
+ }
+
+ private ContentResponse doRequest(Request request, @Nullable Map<String, String> parameters)
+ throws CommunicationException {
+ try {
+ if (parameters != null) {
+ for (String key : parameters.keySet()) {
+ request.param(key, parameters.get(key));
+ }
+ }
+ addCookiesToRequest(request);
+ logger.debug("SleepIQ: doPut: request url={}", request.getURI());
+ ContentResponse response = request.send();
+ logger.trace("SleepIQ: doPut: status={} response={}", response.getStatus(), response.getContentAsString());
+ return response;
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
+ logger.debug("SleepIQ: doPut: Exception message={}", e.getMessage(), e);
+ throw new CommunicationException("Communication error while accessing API: " + e.getMessage());
+ }
+ }
+
+ private void addCookiesToRequest(Request request) {
+ cookieStore.get(config.getBaseUri()).forEach(cookie -> {
+ request.cookie(cookie);
+ });
+ }
+
+ private boolean isUnauthorized(ContentResponse response) {
+ return response.getStatus() == HttpStatus.Code.UNAUTHORIZED.getCode();
+ }
+
+ private boolean isNotOk(ContentResponse response) {
+ return response.getStatus() != HttpStatus.Code.OK.getCode();
+ }
+
+ private synchronized void resetLogin() {
+ logger.debug("SleepIQ: resetLogin: Set loginInfo=null to force login on next transaction");
+ loginInfo = null;
+ }
+}
--- /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.sleepiq.internal.api.impl.typeadapters;
+
+import java.util.function.Function;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Abstract type adapter for jsr310 date-time types.
+ *
+ * @author Christophe Bornet - Initial contribution
+ */
+@NonNullByDefault
+abstract class DateTimeTypeAdapter<T> extends TemporalTypeAdapter<T> {
+
+ DateTimeTypeAdapter(Function<String, T> parseFunction) {
+ super(parseFunction);
+ }
+
+ @Override
+ public String preProcess(String in) {
+ if (in.endsWith("+0000")) {
+ return in.substring(0, in.length() - 5) + "Z";
+ }
+ return in;
+ }
+}
--- /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.sleepiq.internal.api.impl.typeadapters;
+
+import java.lang.reflect.Type;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * The {@link SideTypeAdapter} converts the Side enum to the format expected by the sleepiq API.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class SideTypeAdapter implements JsonDeserializer<Side>, JsonSerializer<Side> {
+
+ @Override
+ public JsonElement serialize(Side side, Type typeOfSrc, JsonSerializationContext context) {
+ return new JsonPrimitive(side.value());
+ }
+
+ @Override
+ public @Nullable Side deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2)
+ throws JsonParseException {
+ int key = element.getAsInt();
+ return Side.forValue(key);
+ }
+}
--- /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.sleepiq.internal.api.impl.typeadapters;
+
+import java.lang.reflect.Type;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepNumberRequest;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * The {@link SleepNumberRequestAdapter} serializes the request to set the sleep number.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class SleepNumberRequestAdapter implements JsonSerializer<SleepNumberRequest> {
+
+ @Override
+ public JsonElement serialize(SleepNumberRequest src, Type typeOfSrc, JsonSerializationContext context) {
+ // Sleep number must be >= 5 and <= 100, and be a multiple of 5
+ int sleepNumber = src.getSleepNumber();
+ sleepNumber = Math.min(100, sleepNumber);
+ sleepNumber = Math.max(5, sleepNumber);
+ sleepNumber = 5 * (int) (Math.round(sleepNumber / 5.0));
+
+ JsonObject obj = new JsonObject();
+ obj.addProperty("bedId", src.getBedId());
+ obj.addProperty("sleepNumber", sleepNumber);
+ obj.addProperty("side", src.getSide().equals(Side.LEFT) ? "L" : "R");
+ return obj;
+ }
+}
--- /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.sleepiq.internal.api.impl.typeadapters;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.function.Function;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+/**
+ * Abstract type adapter for jsr310 date-time types.
+ *
+ * @author Christophe Bornet - Initial contribution
+ */
+@NonNullByDefault
+abstract class TemporalTypeAdapter<T> extends TypeAdapter<T> {
+
+ Function<String, T> parseFunction;
+
+ TemporalTypeAdapter(Function<String, T> parseFunction) {
+ Objects.requireNonNull(parseFunction);
+ this.parseFunction = parseFunction;
+ }
+
+ @Override
+ public void write(JsonWriter out, @Nullable T value) throws IOException {
+ if (value == null) {
+ out.nullValue();
+ } else {
+ out.value(value.toString());
+ }
+ }
+
+ @Override
+ public @Nullable T read(JsonReader in) throws IOException {
+ if (in.peek() == JsonToken.NULL) {
+ in.nextNull();
+ return null;
+ }
+ String temporalString = preProcess(in.nextString());
+ return parseFunction.apply(temporalString);
+ }
+
+ public String preProcess(String in) {
+ return in;
+ }
+}
--- /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.sleepiq.internal.api.impl.typeadapters;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.sleepiq.internal.api.dto.TimeSince;
+
+/**
+ * The {@link TimeSinceTypeAdapter} handles the parsing of the TimeSince.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class TimeSinceTypeAdapter extends TemporalTypeAdapter<TimeSince> {
+ public TimeSinceTypeAdapter() {
+ super(TimeSince::parse);
+ }
+}
--- /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.sleepiq.internal.api.impl.typeadapters;
+
+import java.time.ZonedDateTime;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Type adapter for jsr310 {@link ZonedDateTime} class.
+ *
+ * @author Christophe Bornet - Initial contribution
+ */
+@NonNullByDefault
+public class ZonedDateTimeTypeAdapter extends DateTimeTypeAdapter<ZonedDateTime> {
+
+ public ZonedDateTimeTypeAdapter() {
+ super(ZonedDateTime::parse);
+ }
+}
*/
package org.openhab.binding.sleepiq.internal.config;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
/**
* Configuration class for a SleepIQ bed.
*
* @author Gregory Moyer - Initial contribution
*/
+@NonNullByDefault
public class SleepIQBedConfiguration {
public static final String BED_ID = "bedId";
- public String bedId;
+ public @Nullable String bedId;
}
package org.openhab.binding.sleepiq.internal.discovery;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
-import org.openhab.binding.sleepiq.api.model.Bed;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.sleepiq.internal.SleepIQBindingConstants;
+import org.openhab.binding.sleepiq.internal.api.dto.Bed;
import org.openhab.binding.sleepiq.internal.config.SleepIQBedConfiguration;
import org.openhab.binding.sleepiq.internal.handler.SleepIQCloudHandler;
import org.openhab.binding.sleepiq.internal.handler.SleepIQDualBedHandler;
*
* @author Gregory Moyer - Initial contribution
*/
+@NonNullByDefault
public class SleepIQBedDiscoveryService extends AbstractDiscoveryService {
private static final int TIMEOUT = 60;
@Override
protected void startScan() {
logger.debug("Starting scan for new beds");
+ List<Bed> beds = cloudHandler.getBeds();
+ if (beds != null) {
+ for (Bed bed : beds) {
+ // only dual chamber beds are supported currently
+ if (!bed.isDualSleep()) {
+ logger.info("Found a bed that is not dual chamber - currently unsupported");
+ continue;
+ }
- for (Bed bed : cloudHandler.getBeds()) {
- // only dual chamber beds are supported currently
- if (!bed.isDualSleep()) {
- logger.info("Found a bed that is not dual chamber - currently unsupported");
- continue;
- }
-
- ThingUID bridgeUID = cloudHandler.getThing().getUID();
- ThingUID thingUID = new ThingUID(SleepIQBindingConstants.THING_TYPE_DUAL_BED, bridgeUID,
- bed.getMacAddress());
-
- // thing already exists
- if (cloudHandler.getThing().getThing(thingUID) != null) {
- continue;
- }
+ ThingUID bridgeUID = cloudHandler.getThing().getUID();
+ ThingUID thingUID = new ThingUID(SleepIQBindingConstants.THING_TYPE_DUAL_BED, bridgeUID,
+ bed.getMacAddress());
- logger.debug("New bed found with MAC address {}", bed.getMacAddress());
+ // thing already exists
+ if (cloudHandler.getThing().getThing(thingUID) != null) {
+ continue;
+ }
- @SuppressWarnings({ "unchecked", "rawtypes" })
- Map<String, Object> properties = (Map) cloudHandler.updateProperties(bed, new HashMap<>());
- properties.put(SleepIQBedConfiguration.BED_ID, bed.getBedId());
+ logger.debug("New bed found with MAC address {}", bed.getMacAddress());
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ Map<String, Object> properties = (Map) cloudHandler.updateProperties(bed, new HashMap<>());
+ properties.put(SleepIQBedConfiguration.BED_ID, bed.getBedId());
- DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
- .withBridge(bridgeUID).withLabel(bed.getName() + " - " + bed.getModel()).build();
- thingDiscovered(discoveryResult);
+ DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
+ .withBridge(bridgeUID).withLabel(bed.getName() + " - " + bed.getModel()).build();
+ thingDiscovered(discoveryResult);
+ }
}
-
stopScan();
}
}
*/
package org.openhab.binding.sleepiq.internal.handler;
-import org.openhab.binding.sleepiq.api.SleepIQ;
-import org.openhab.binding.sleepiq.api.model.BedStatus;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.sleepiq.internal.api.dto.BedStatus;
+import org.openhab.binding.sleepiq.internal.api.dto.Sleeper;
/**
* The {@link BedStatusListener} is notified when a chamber is updated.
*
* @author Gregory Moyer - Initial contribution
*/
+@NonNullByDefault
public interface BedStatusListener {
/**
* This method will be called whenever a new bed status is received by the cloud handler.
* @param cloud the cloud service that can be used to gather additional information
* @param status the status returned from the cloud service
*/
- public void onBedStateChanged(SleepIQ cloud, BedStatus status);
+ public void onBedStateChanged(BedStatus status);
+
+ public void onSleeperChanged(@Nullable Sleeper sleeper);
}
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-import javax.ws.rs.client.ClientBuilder;
-
-import org.openhab.binding.sleepiq.api.Configuration;
-import org.openhab.binding.sleepiq.api.LoginException;
-import org.openhab.binding.sleepiq.api.SleepIQ;
-import org.openhab.binding.sleepiq.api.UnauthorizedException;
-import org.openhab.binding.sleepiq.api.model.Bed;
-import org.openhab.binding.sleepiq.api.model.BedStatus;
-import org.openhab.binding.sleepiq.api.model.FamilyStatus;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.sleepiq.internal.SleepIQBindingConstants;
import org.openhab.binding.sleepiq.internal.SleepIQConfigStatusMessage;
+import org.openhab.binding.sleepiq.internal.api.Configuration;
+import org.openhab.binding.sleepiq.internal.api.LoginException;
+import org.openhab.binding.sleepiq.internal.api.SleepIQ;
+import org.openhab.binding.sleepiq.internal.api.SleepIQException;
+import org.openhab.binding.sleepiq.internal.api.UnauthorizedException;
+import org.openhab.binding.sleepiq.internal.api.dto.Bed;
+import org.openhab.binding.sleepiq.internal.api.dto.BedStatus;
+import org.openhab.binding.sleepiq.internal.api.dto.FamilyStatusResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepDataResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.Sleeper;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+import org.openhab.binding.sleepiq.internal.api.enums.SleepDataInterval;
import org.openhab.binding.sleepiq.internal.config.SleepIQCloudConfiguration;
-import org.openhab.core.cache.ExpiringCache;
import org.openhab.core.config.core.status.ConfigStatusMessage;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
*
* @author Gregory Moyer - Initial contribution
*/
+@NonNullByDefault
public class SleepIQCloudHandler extends ConfigStatusBridgeHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Collections.singleton(THING_TYPE_CLOUD);
+ private static final int SLEEPER_POLLING_INTERVAL_HOURS = 12;
+
private final Logger logger = LoggerFactory.getLogger(SleepIQCloudHandler.class);
- private final List<BedStatusListener> bedStatusListeners = new CopyOnWriteArrayList<>();
+ private final HttpClient httpClient;
- private ExpiringCache<FamilyStatus> statusCache;
+ private final List<BedStatusListener> bedStatusListeners = new CopyOnWriteArrayList<>();
- private ScheduledFuture<?> pollingJob;
+ private @Nullable ScheduledFuture<?> statusPollingJob;
+ private @Nullable ScheduledFuture<?> sleeperPollingJob;
- private SleepIQ cloud;
+ private @Nullable SleepIQ cloud;
- private ClientBuilder clientBuilder;
+ private @Nullable List<Sleeper> sleepers;
- public SleepIQCloudHandler(final Bridge bridge, ClientBuilder clientBuilder) {
+ public SleepIQCloudHandler(final Bridge bridge, HttpClient httpClient) {
super(bridge);
- this.clientBuilder = clientBuilder;
+ this.httpClient = httpClient;
}
@Override
public void initialize() {
- try {
- logger.debug("Configuring bed status cache");
- statusCache = new ExpiringCache<>(TimeUnit.SECONDS.toMillis(getPollingInterval() / 2),
- () -> cloud.getFamilyStatus());
-
- createCloudConnection();
-
- logger.debug("Setting SleepIQ cloud online");
- updateListenerManagement();
- updateStatus(ThingStatus.ONLINE);
- } catch (UnauthorizedException e) {
- logger.debug("SleepIQ cloud authentication failed", e);
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid SleepIQ credentials");
- } catch (LoginException e) {
- logger.debug("SleepIQ cloud login failed", e);
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "SleepIQ cloud login failed: " + e.getMessage());
- } catch (Exception e) {
- logger.debug("Unexpected error while communicating with SleepIQ cloud", e);
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "Unable to connect to SleepIQ cloud: " + e.getMessage());
- }
- }
-
- /**
- * Create a new SleepIQ cloud service connection. If a connection already exists, it will be lost.
- *
- * @param clientBuilder2
- *
- * @throws LoginException if there is an error while authenticating to the service
- */
- private void createCloudConnection() throws LoginException {
- logger.debug("Reading SleepIQ cloud binding configuration");
- SleepIQCloudConfiguration bindingConfig = getConfigAs(SleepIQCloudConfiguration.class);
-
- logger.debug("Creating SleepIQ client");
- Configuration cloudConfig = new Configuration().withUsername(bindingConfig.username)
- .withPassword(bindingConfig.password).withLogging(logger.isDebugEnabled());
- cloud = SleepIQ.create(cloudConfig, clientBuilder);
-
- logger.debug("Authenticating at the SleepIQ cloud service");
- cloud.login();
-
- logger.info("Successfully authenticated at the SleepIQ cloud service");
+ scheduler.execute(() -> {
+ try {
+ createCloudConnection();
+ updateListenerManagement();
+ updateStatus(ThingStatus.ONLINE);
+ } catch (UnauthorizedException e) {
+ logger.debug("CloudHandler: SleepIQ cloud authentication failed", e);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid SleepIQ credentials");
+ } catch (LoginException e) {
+ logger.debug("CloudHandler: SleepIQ cloud login failed", e);
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "SleepIQ cloud login failed: " + e.getMessage());
+ }
+ });
}
@Override
public synchronized void dispose() {
- logger.debug("Disposing SleepIQ cloud handler");
-
- if (pollingJob != null && !pollingJob.isCancelled()) {
- pollingJob.cancel(true);
- pollingJob = null;
+ stopSleeperPollingJob();
+ stopStatusPollingJob();
+ if (cloud != null) {
+ cloud.shutdown();
}
}
- /**
- * Start or stop a background polling job to look for bed status updates based on whether or not there are any
- * listeners to notify.
- */
- private synchronized void updateListenerManagement() {
- if (!bedStatusListeners.isEmpty() && (pollingJob == null || pollingJob.isCancelled())) {
- int pollingInterval = getPollingInterval();
- pollingJob = scheduler.scheduleWithFixedDelay(this::refreshBedStatus, pollingInterval, pollingInterval,
- TimeUnit.SECONDS);
- } else if (bedStatusListeners.isEmpty() && pollingJob != null && !pollingJob.isCancelled()) {
- pollingJob.cancel(true);
- pollingJob = null;
- }
+ @Override
+ public void handleCommand(final ChannelUID channelUID, final Command command) {
+ // cloud handler has no channels
}
/**
- * Retrieve the polling interval for updating bed status.
+ * Validate the config from openHAB
*
- * @return the polling interval in seconds
+ * @return validity status of config parameters
*/
- private int getPollingInterval() {
- return getConfigAs(SleepIQCloudConfiguration.class).pollingInterval;
- }
-
- /**
- * Retrieve the latest status on all beds and update all registered listeners.
- */
- public void refreshBedStatus() {
- try {
- FamilyStatus status = statusCache.getValue();
- updateStatus(ThingStatus.ONLINE);
-
- for (BedStatus bedStatus : status.getBeds()) {
- bedStatusListeners.stream().forEach(l -> l.onBedStateChanged(cloud, bedStatus));
- }
- } catch (Exception e) {
- logger.debug("Unexpected error while communicating with SleepIQ cloud", e);
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "Unable to connect to SleepIQ cloud: " + e.getMessage());
+ @Override
+ public Collection<ConfigStatusMessage> getConfigStatus() {
+ Collection<ConfigStatusMessage> configStatusMessages = new ArrayList<>();
+ SleepIQCloudConfiguration config = getConfigAs(SleepIQCloudConfiguration.class);
+ String username = config.username;
+ String password = config.password;
+ if (username.isBlank()) {
+ configStatusMessages.add(ConfigStatusMessage.Builder.error(USERNAME)
+ .withMessageKeySuffix(SleepIQConfigStatusMessage.USERNAME_MISSING).withArguments(USERNAME).build());
}
+ if (password.isBlank()) {
+ configStatusMessages.add(ConfigStatusMessage.Builder.error(PASSWORD)
+ .withMessageKeySuffix(SleepIQConfigStatusMessage.PASSWORD_MISSING).withArguments(PASSWORD).build());
+ }
+ return configStatusMessages;
}
/**
* @param listener the listener to register
*/
public void registerBedStatusListener(final BedStatusListener listener) {
- if (listener == null) {
- return;
- }
-
bedStatusListeners.add(listener);
- refreshBedStatus();
- updateListenerManagement();
+ scheduler.execute(() -> {
+ refreshSleepers();
+ refreshBedStatus();
+ updateListenerManagement();
+ });
}
/**
if (result) {
updateListenerManagement();
}
-
return result;
}
- @Override
- public void handleCommand(final ChannelUID channelUID, final Command command) {
- // cloud handler has no channels
+ /**
+ * Get a list of all beds registered to the cloud service account.
+ *
+ * @return the list of beds or null if unable to get list
+ */
+ public @Nullable List<Bed> getBeds() {
+ try {
+ return cloud.getBeds();
+ } catch (SleepIQException e) {
+ logger.debug("CloudHandler: Exception getting list of beds", e);
+ return null;
+ }
}
- @Override
- public Collection<ConfigStatusMessage> getConfigStatus() {
- Collection<ConfigStatusMessage> configStatusMessages = new ArrayList<>();
-
- SleepIQCloudConfiguration config = getConfigAs(SleepIQCloudConfiguration.class);
- String username = config.username;
- String password = config.password;
-
- if (username.isEmpty()) {
- configStatusMessages.add(ConfigStatusMessage.Builder.error(USERNAME)
- .withMessageKeySuffix(SleepIQConfigStatusMessage.USERNAME_MISSING).withArguments(USERNAME).build());
+ /**
+ * Get the bed corresponding to the given bed id
+ *
+ * @param bedId the bed identifier
+ * @return the identified {@link Bed} or <code>null</code> if no such bed exists
+ */
+ public @Nullable Bed getBed(final @Nullable String bedId) {
+ logger.debug("CloudHandler: Get bed object for bedId={}", bedId);
+ if (bedId == null) {
+ return null;
}
-
- if (password.isEmpty()) {
- configStatusMessages.add(ConfigStatusMessage.Builder.error(PASSWORD)
- .withMessageKeySuffix(SleepIQConfigStatusMessage.PASSWORD_MISSING).withArguments(PASSWORD).build());
+ List<Bed> beds = getBeds();
+ if (beds != null) {
+ for (Bed bed : beds) {
+ if (bedId.equals(bed.getBedId())) {
+ return bed;
+ }
+ }
}
-
- return configStatusMessages;
+ return null;
}
/**
- * Get a list of all beds registered to the cloud service account.
+ * Get the sleeper associated with the bedId and side
*
- * @return the list of beds (never <code>null</code>)
+ * @param bedId the bed identifier
+ * @param side the side of the bed
+ * @return the sleeper or null if sleeper not found
*/
- public List<Bed> getBeds() {
- return cloud.getBeds();
+ public @Nullable Sleeper getSleeper(@Nullable String bedId, Side side) {
+ logger.debug("CloudHandler: Get sleeper object for bedId={}, side={}", bedId, side);
+ if (bedId == null) {
+ return null;
+ }
+ List<Sleeper> localSleepers = sleepers;
+ if (localSleepers != null) {
+ for (Sleeper sleeper : localSleepers) {
+ if (bedId.equals(sleeper.getBedId()) && side.equals(sleeper.getSide())) {
+ return sleeper;
+ }
+ }
+ }
+ return null;
}
/**
- * Get the {@link Bed} corresponding to the given identifier.
+ * Set the sleep number of the specified chamber
*
* @param bedId the bed identifier
- * @return the identified {@link Bed} or <code>null</code> if no such bed exists
+ * @param sleepNumber the sleep number multiple of 5 between 5 and 100
+ * @param side the chamber to set
*/
- public Bed getBed(final String bedId) {
- for (Bed bed : getBeds()) {
- if (bedId.equals(bed.getBedId())) {
- return bed;
- }
+ public void setSleepNumber(@Nullable String bedId, Side side, int sleepNumber) {
+ if (bedId == null) {
+ return;
}
+ try {
+ cloud.setSleepNumber(bedId, side, sleepNumber);
+ } catch (SleepIQException e) {
+ logger.debug("CloudHandler: Exception setting sleep number of bed={}", bedId, e);
+ }
+ }
- return null;
+ /**
+ * Set the pause mode of the specified bed
+ *
+ * @param bedId the bed identifier
+ * @param mode turn pause mode on or off
+ */
+ public void setPauseMode(@Nullable String bedId, boolean mode) {
+ if (bedId == null) {
+ return;
+ }
+ try {
+ cloud.setPauseMode(bedId, mode);
+ } catch (SleepIQException e) {
+ logger.debug("CloudHandler: Exception setting pause mode of bed={}", bedId, e);
+ }
}
/**
* @param properties the properties to update (this may be <code>null</code>)
* @return the given map (or a new map if no map was given) with updated/set properties from the supplied bed
*/
- public Map<String, String> updateProperties(final Bed bed, Map<String, String> properties) {
+ public Map<String, String> updateProperties(final @Nullable Bed bed, Map<String, String> properties) {
if (bed != null) {
+ logger.debug("CloudHandler: Updating bed properties for bed={}", bed.getBedId());
properties.put(Thing.PROPERTY_MODEL_ID, bed.getModel());
properties.put(SleepIQBindingConstants.PROPERTY_BASE, bed.getBase());
if (bed.isKidsBed() != null) {
properties.put(SleepIQBindingConstants.PROPERTY_SIZE, bed.getSize());
properties.put(SleepIQBindingConstants.PROPERTY_SKU, bed.getSku());
}
-
return properties;
}
+
+ /**
+ * Retrieve the latest status on all beds and update all registered listeners
+ * with bed status, sleepers and sleep data.
+ */
+ private void refreshBedStatus() {
+ logger.debug("CloudHandler: Refreshing BED STATUS, updating chanels with status, sleepers, and sleep data");
+ try {
+ FamilyStatusResponse familyStatus = cloud.getFamilyStatus();
+ if (familyStatus != null && familyStatus.getBeds() != null) {
+ updateStatus(ThingStatus.ONLINE);
+ for (BedStatus bedStatus : familyStatus.getBeds()) {
+ logger.debug("CloudHandler: Informing listeners with bed status for bedId={}",
+ bedStatus.getBedId());
+ bedStatusListeners.stream().forEach(l -> l.onBedStateChanged(bedStatus));
+ }
+
+ List<Sleeper> localSleepers = sleepers;
+ if (localSleepers != null) {
+ for (Sleeper sleeper : localSleepers) {
+ logger.debug("CloudHandler: Informing listeners with sleepers for sleeperId={}",
+ sleeper.getSleeperId());
+ bedStatusListeners.stream().forEach(l -> l.onSleeperChanged(sleeper));
+ }
+ }
+ return;
+ }
+ } catch (SleepIQException e) {
+ logger.debug("CloudHandler: Exception refreshing bed status", e);
+ }
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Unable to connect to SleepIQ cloud");
+ }
+
+ /**
+ * Refresh the list of sleepers
+ */
+ private void refreshSleepers() {
+ logger.debug("CloudHandler: Refreshing SLEEPERS");
+ try {
+ sleepers = cloud.getSleepers();
+ } catch (SleepIQException e) {
+ logger.debug("CloudHandler: Exception refreshing list of sleepers", e);
+ }
+ }
+
+ public @Nullable SleepDataResponse getDailySleepData(String sleeperId) {
+ return getSleepData(sleeperId, SleepDataInterval.DAY);
+ }
+
+ public @Nullable SleepDataResponse getMonthlySleepData(String sleeperId) {
+ return getSleepData(sleeperId, SleepDataInterval.MONTH);
+ }
+
+ private @Nullable SleepDataResponse getSleepData(String sleeperId, SleepDataInterval interval) {
+ try {
+ return cloud.getSleepData(sleeperId, interval);
+ } catch (SleepIQException e) {
+ logger.debug("CloudHandler: Exception getting sleep data for sleeperId={}", sleeperId, e);
+ }
+ return null;
+ }
+
+ /**
+ * Create a new SleepIQ cloud service connection. If a connection already exists, it will be lost.
+ *
+ * @throws LoginException if there is an error while authenticating to the service
+ */
+ private void createCloudConnection() throws LoginException {
+ SleepIQCloudConfiguration bindingConfig = getConfigAs(SleepIQCloudConfiguration.class);
+ Configuration cloudConfig = new Configuration().withUsername(bindingConfig.username)
+ .withPassword(bindingConfig.password).withLogging(logger.isTraceEnabled());
+ logger.debug("CloudHandler: Authenticating at the SleepIQ cloud service");
+ cloud = SleepIQ.create(cloudConfig, httpClient);
+ cloud.login();
+ }
+
+ /**
+ * Start or stop the background polling jobs
+ */
+ private synchronized void updateListenerManagement() {
+ startSleeperPollingJob();
+ startStatusPollingJob();
+ }
+
+ /**
+ * Start or stop the bed status polling job
+ */
+ private void startStatusPollingJob() {
+ ScheduledFuture<?> localPollingJob = statusPollingJob;
+ if (!bedStatusListeners.isEmpty() && (localPollingJob == null || localPollingJob.isCancelled())) {
+ int pollingInterval = getStatusPollingIntervalSeconds();
+ logger.debug("CloudHandler: Scheduling bed status polling job every {} seconds", pollingInterval);
+ statusPollingJob = scheduler.scheduleWithFixedDelay(this::refreshBedStatus, pollingInterval,
+ pollingInterval, TimeUnit.SECONDS);
+ } else if (bedStatusListeners.isEmpty()) {
+ stopStatusPollingJob();
+ }
+ }
+
+ /**
+ * Stop the bed status polling job
+ */
+ private void stopStatusPollingJob() {
+ ScheduledFuture<?> localPollingJob = statusPollingJob;
+ if (localPollingJob != null) {
+ logger.debug("CloudHandler: Canceling bed status polling job");
+ localPollingJob.cancel(true);
+ statusPollingJob = null;
+ }
+ }
+
+ private int getStatusPollingIntervalSeconds() {
+ return getConfigAs(SleepIQCloudConfiguration.class).pollingInterval;
+ }
+
+ /**
+ * Start or stop the sleeper polling job
+ */
+ private void startSleeperPollingJob() {
+ ScheduledFuture<?> localJob = sleeperPollingJob;
+ if (!bedStatusListeners.isEmpty() && (localJob == null || localJob.isCancelled())) {
+ logger.debug("CloudHandler: Scheduling sleeper polling job every {} hours", SLEEPER_POLLING_INTERVAL_HOURS);
+ sleeperPollingJob = scheduler.scheduleWithFixedDelay(this::refreshSleepers, SLEEPER_POLLING_INTERVAL_HOURS,
+ SLEEPER_POLLING_INTERVAL_HOURS, TimeUnit.HOURS);
+ } else if (bedStatusListeners.isEmpty()) {
+ stopSleeperPollingJob();
+ }
+ }
+
+ /**
+ * Stop the sleeper polling job
+ */
+ private void stopSleeperPollingJob() {
+ ScheduledFuture<?> localJob = sleeperPollingJob;
+ if (localJob != null && !localJob.isCancelled()) {
+ logger.debug("CloudHandler: Canceling sleeper polling job");
+ localJob.cancel(true);
+ sleeperPollingJob = null;
+ }
+ }
}
import java.util.Collections;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
-import org.openhab.binding.sleepiq.api.SleepIQ;
-import org.openhab.binding.sleepiq.api.model.Bed;
-import org.openhab.binding.sleepiq.api.model.BedSideStatus;
-import org.openhab.binding.sleepiq.api.model.BedStatus;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.binding.sleepiq.internal.api.dto.Bed;
+import org.openhab.binding.sleepiq.internal.api.dto.BedSideStatus;
+import org.openhab.binding.sleepiq.internal.api.dto.BedStatus;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepDataResponse;
+import org.openhab.binding.sleepiq.internal.api.dto.Sleeper;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
import org.openhab.binding.sleepiq.internal.config.SleepIQBedConfiguration;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
+import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
-import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
+import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*
* @author Gregory Moyer - Initial contribution
*/
+@NonNullByDefault
public class SleepIQDualBedHandler extends BaseThingHandler implements BedStatusListener {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Collections.singleton(THING_TYPE_DUAL_BED);
+ private static final long GET_SLEEP_DATA_DELAY_MINUTES = 5;
+
private final Logger logger = LoggerFactory.getLogger(SleepIQDualBedHandler.class);
- private volatile String bedId;
+ private volatile @Nullable String bedId;
+
+ private @Nullable Sleeper sleeperLeft;
+ private @Nullable Sleeper sleeperRight;
+
+ private @Nullable BedStatus previousStatus;
public SleepIQDualBedHandler(final Thing thing) {
super(thing);
@Override
public void initialize() {
- logger.debug("Verifying SleepIQ cloud/bridge configuration");
-
Bridge bridge = getBridge();
if (bridge == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"No cloud service bridge has been configured");
return;
}
-
ThingHandler handler = bridge.getHandler();
if (!(handler instanceof SleepIQCloudHandler)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Incorrect bridge thing found");
return;
}
-
- logger.debug("Reading SleepIQ bed binding configuration");
bedId = getConfigAs(SleepIQBedConfiguration.class).bedId;
+ if (bedId == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "Bed id not found in configuration");
+ return;
+ }
- logger.debug("Registering SleepIQ bed status listener");
+ logger.debug("BedHandler: Registering SleepIQ bed status listener for bedId={}", bedId);
SleepIQCloudHandler cloudHandler = (SleepIQCloudHandler) handler;
cloudHandler.registerBedStatusListener(this);
if (ThingStatus.ONLINE != bridge.getStatus()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
} else {
- updateProperties();
updateStatus(ThingStatus.ONLINE);
+ scheduler.execute(() -> {
+ updateProperties();
+ });
+ }
+ }
+
+ @Override
+ public void dispose() {
+ SleepIQCloudHandler cloudHandler = getCloudHandler();
+ if (cloudHandler != null) {
+ cloudHandler.unregisterBedStatusListener(this);
}
+ bedId = null;
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
super.bridgeStatusChanged(bridgeStatusInfo);
-
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
updateProperties();
}
}
- private void updateProperties() {
- logger.debug("Updating SleepIQ bed properties for bed {}", bedId);
-
- SleepIQCloudHandler cloudHandler = (SleepIQCloudHandler) getBridge().getHandler();
- Bed bed = cloudHandler.getBed(bedId);
- if (bed == null) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bed found with ID " + bedId);
+ @Override
+ public void handleCommand(final ChannelUID channelUID, final Command command) {
+ if (command == RefreshType.REFRESH) {
+ // Channels will be refreshed automatically by cloud handler
return;
}
- updateProperties(cloudHandler.updateProperties(bed, editProperties()));
+ switch (channelUID.getId()) {
+ case CHANNEL_LEFT_SLEEP_NUMBER:
+ case CHANNEL_RIGHT_SLEEP_NUMBER:
+ if (command instanceof DecimalType) {
+ Side side = Side.convertFromGroup(channelUID.getGroupId());
+ logger.debug("BedHandler: Set sleepnumber to {} for bedId={}, side={}", command, bedId, side);
+ SleepIQCloudHandler cloudHandler = getCloudHandler();
+ if (cloudHandler != null) {
+ cloudHandler.setSleepNumber(bedId, side, ((DecimalType) command).intValue());
+ }
+ }
+ break;
+ case CHANNEL_LEFT_PRIVACY_MODE:
+ case CHANNEL_RIGHT_PRIVACY_MODE:
+ if (command instanceof OnOffType) {
+ Side side = Side.convertFromGroup(channelUID.getGroupId());
+ logger.debug("BedHandler: Set sleepnumber to {} for bedId={}, side={}", command, bedId, side);
+ SleepIQCloudHandler cloudHandler = getCloudHandler();
+ if (cloudHandler != null) {
+ cloudHandler.setPauseMode(bedId, command == OnOffType.ON ? true : false);
+ }
+ }
+ break;
+ }
}
@Override
- public void dispose() {
- logger.debug("Disposing bed handler for bed {}", bedId);
-
- Bridge bridge = getBridge();
- if (bridge != null) {
- BridgeHandler bridgeHandler = bridge.getHandler();
- if (bridgeHandler instanceof SleepIQCloudHandler) {
- ((SleepIQCloudHandler) bridgeHandler).unregisterBedStatusListener(this);
- }
+ public void onSleeperChanged(final @Nullable Sleeper sleeper) {
+ if (sleeper == null || !sleeper.getBedId().equals(bedId)) {
+ return;
}
+ logger.debug("BedHandler: Updating sleeper information channels for bed={}, side={}", bedId, sleeper.getSide());
- bedId = null;
+ if (sleeper.getSide().equals(Side.LEFT)) {
+ sleeperLeft = sleeper;
+ updateState(CHANNEL_LEFT_FIRST_NAME, new StringType(sleeper.getFirstName()));
+ updateState(CHANNEL_LEFT_SLEEP_GOAL_MINUTES, new QuantityType<>(sleeper.getSleepGoal(), Units.MINUTE));
+ } else {
+ sleeperRight = sleeper;
+ updateState(CHANNEL_RIGHT_FIRST_NAME, new StringType(sleeper.getFirstName()));
+ updateState(CHANNEL_RIGHT_SLEEP_GOAL_MINUTES, new QuantityType<>(sleeper.getSleepGoal(), Units.MINUTE));
+ }
}
@Override
- public void onBedStateChanged(final SleepIQ cloud, final BedStatus status) {
- if (!status.getBedId().equals(bedId)) {
+ public void onBedStateChanged(final @Nullable BedStatus status) {
+ if (status == null || !status.getBedId().equals(bedId)) {
return;
}
+ logger.debug("BedHandler: Updating bed status channels for bed {}", bedId);
- logger.debug("Updating left side status for bed {}", bedId);
BedSideStatus left = status.getLeftSide();
updateState(CHANNEL_LEFT_IN_BED, left.isInBed() ? OnOffType.ON : OnOffType.OFF);
updateState(CHANNEL_LEFT_SLEEP_NUMBER, new DecimalType(left.getSleepNumber()));
updateState(CHANNEL_LEFT_LAST_LINK, new StringType(left.getLastLink().toString()));
updateState(CHANNEL_LEFT_ALERT_ID, new DecimalType(left.getAlertId()));
updateState(CHANNEL_LEFT_ALERT_DETAILED_MESSAGE, new StringType(left.getAlertDetailedMessage()));
+ if (previousStatus != null) {
+ updateSleepDataChannels(previousStatus.getLeftSide(), left, sleeperLeft);
+ }
- logger.debug("Updating right side status for bed {}", bedId);
BedSideStatus right = status.getRightSide();
updateState(CHANNEL_RIGHT_IN_BED, right.isInBed() ? OnOffType.ON : OnOffType.OFF);
updateState(CHANNEL_RIGHT_SLEEP_NUMBER, new DecimalType(right.getSleepNumber()));
updateState(CHANNEL_RIGHT_LAST_LINK, new StringType(right.getLastLink().toString()));
updateState(CHANNEL_RIGHT_ALERT_ID, new DecimalType(right.getAlertId()));
updateState(CHANNEL_RIGHT_ALERT_DETAILED_MESSAGE, new StringType(right.getAlertDetailedMessage()));
+ if (previousStatus != null) {
+ updateSleepDataChannels(previousStatus.getRightSide(), right, sleeperRight);
+ }
+
+ previousStatus = status;
}
- @Override
- public void handleCommand(final ChannelUID channelUID, final Command command) {
- // all channels are read-only
+ private void updateSleepDataChannels(BedSideStatus previousSideStatus, BedSideStatus currentSideStatus,
+ @Nullable Sleeper sleeper) {
+ if (sleeper == null) {
+ logger.debug("BedHandler: Can't update sleep data channels because sleeper is null");
+ return;
+ }
+ if (previousSideStatus.isInBed() && !currentSideStatus.isInBed()) {
+ logger.debug("BedHandler: Bed status changed from IN BED to OUT OF BED for {}, side {}", bedId,
+ sleeper.getSide());
+ scheduler.schedule(() -> {
+ updateDailySleepDataChannels(sleeper);
+ updateMonthlySleepDataChannels(sleeper);
+ }, GET_SLEEP_DATA_DELAY_MINUTES, TimeUnit.MINUTES);
+ }
+ }
- if (command == RefreshType.REFRESH) {
- SleepIQCloudHandler cloudHandler = (SleepIQCloudHandler) getBridge().getHandler();
- cloudHandler.refreshBedStatus();
+ public void updateDailySleepDataChannels(final @Nullable Sleeper sleeper) {
+ SleepIQCloudHandler cloudHandler = getCloudHandler();
+ if (cloudHandler == null || sleeper == null) {
+ return;
+ }
+ SleepDataResponse sleepData = cloudHandler.getDailySleepData(sleeper.getSleeperId());
+ if (sleepData == null) {
+ logger.debug("BedHandler: Received no daily sleep data for bedId={}, sleeperId={}", sleeper.getBedId(),
+ sleeper.getSleeperId());
+ return;
+ }
+
+ logger.debug("BedHandler: UPDATING DAILY SLEEP DATA CHANNELS for bedId={}, sleeperId={}", sleeper.getBedId(),
+ sleeper.getSleeperId());
+ if (sleepData.getSleepDataDays() == null || sleepData.getSleepDataDays().size() != 1) {
+ if (sleeper.getSide().equals(Side.LEFT)) {
+ updateState(CHANNEL_LEFT_TODAY_SLEEP_IQ, UnDefType.UNDEF);
+ updateState(CHANNEL_LEFT_TODAY_AVG_HEART_RATE, UnDefType.UNDEF);
+ updateState(CHANNEL_LEFT_TODAY_AVG_RESPIRATION_RATE, UnDefType.UNDEF);
+ updateState(CHANNEL_LEFT_TODAY_MESSAGE, UnDefType.UNDEF);
+ updateState(CHANNEL_LEFT_TODAY_SLEEP_DURATION_SECONDS, UnDefType.UNDEF);
+ } else {
+ updateState(CHANNEL_RIGHT_TODAY_SLEEP_IQ, UnDefType.UNDEF);
+ updateState(CHANNEL_RIGHT_TODAY_AVG_HEART_RATE, UnDefType.UNDEF);
+ updateState(CHANNEL_RIGHT_TODAY_AVG_RESPIRATION_RATE, UnDefType.UNDEF);
+ updateState(CHANNEL_RIGHT_TODAY_MESSAGE, UnDefType.UNDEF);
+ updateState(CHANNEL_RIGHT_TODAY_SLEEP_DURATION_SECONDS, UnDefType.UNDEF);
+ }
+ return;
+ } else if (sleeper.getSide().equals(Side.LEFT)) {
+ updateState(CHANNEL_LEFT_TODAY_SLEEP_IQ, new DecimalType(sleepData.getAverageSleepIQ()));
+ updateState(CHANNEL_LEFT_TODAY_AVG_HEART_RATE, new DecimalType(sleepData.getAverageHeartRate()));
+ updateState(CHANNEL_LEFT_TODAY_AVG_RESPIRATION_RATE,
+ new DecimalType(sleepData.getAverageRespirationRate()));
+ updateState(CHANNEL_LEFT_TODAY_MESSAGE, new StringType(sleepData.getSleepDataDays().get(0).getMessage()));
+ updateState(CHANNEL_LEFT_TODAY_SLEEP_DURATION_SECONDS,
+ new QuantityType<>(sleepData.getTotalSleepSessionTime(), Units.SECOND));
+ } else if (sleeper.getSide().equals(Side.RIGHT)) {
+ updateState(CHANNEL_RIGHT_TODAY_SLEEP_IQ, new DecimalType(sleepData.getAverageSleepIQ()));
+ updateState(CHANNEL_RIGHT_TODAY_AVG_HEART_RATE, new DecimalType(sleepData.getAverageHeartRate()));
+ updateState(CHANNEL_RIGHT_TODAY_AVG_RESPIRATION_RATE,
+ new DecimalType(sleepData.getAverageRespirationRate()));
+ updateState(CHANNEL_RIGHT_TODAY_MESSAGE, new StringType(sleepData.getSleepDataDays().get(0).getMessage()));
+ updateState(CHANNEL_RIGHT_TODAY_SLEEP_DURATION_SECONDS,
+ new QuantityType<>(sleepData.getTotalSleepSessionTime(), Units.SECOND));
+ }
+ }
+
+ public void updateMonthlySleepDataChannels(final @Nullable Sleeper sleeper) {
+ SleepIQCloudHandler cloudHandler = getCloudHandler();
+ if (cloudHandler == null || sleeper == null) {
+ return;
+ }
+ SleepDataResponse sleepData = cloudHandler.getMonthlySleepData(sleeper.getSleeperId());
+ if (sleepData == null) {
+ logger.debug("BedHandler: Received no monthly sleep data for bedId={}, sleeperId={}", sleeper.getBedId(),
+ sleeper.getSleeperId());
+ return;
+ }
+
+ logger.debug("BedHandler: UPDATING MONTHLY SLEEP DATA CHANNELS for bedId={}, sleeperId={}", sleeper.getBedId(),
+ sleeper.getSleeperId());
+ if (sleeper.getSide().equals(Side.LEFT)) {
+ updateState(CHANNEL_LEFT_MONTHLY_SLEEP_IQ, new DecimalType(sleepData.getAverageSleepIQ()));
+ updateState(CHANNEL_LEFT_MONTHLY_AVG_HEART_RATE, new DecimalType(sleepData.getAverageHeartRate()));
+ updateState(CHANNEL_LEFT_MONTHLY_AVG_RESPIRATION_RATE,
+ new DecimalType(sleepData.getAverageRespirationRate()));
+ } else {
+ updateState(CHANNEL_RIGHT_MONTHLY_SLEEP_IQ, new DecimalType(sleepData.getAverageSleepIQ()));
+ updateState(CHANNEL_RIGHT_MONTHLY_AVG_HEART_RATE, new DecimalType(sleepData.getAverageHeartRate()));
+ updateState(CHANNEL_RIGHT_MONTHLY_AVG_RESPIRATION_RATE,
+ new DecimalType(sleepData.getAverageRespirationRate()));
+ }
+ }
+
+ private void updateProperties() {
+ logger.debug("BedHandler: Updating bed properties for bedId={}", bedId);
+ SleepIQCloudHandler cloudHandler = getCloudHandler();
+ if (cloudHandler != null) {
+ Bed bed = cloudHandler.getBed(bedId);
+ if (bed == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "No bed found with ID " + bedId);
+ return;
+ }
+ updateProperties(cloudHandler.updateProperties(bed, editProperties()));
+ }
+ }
+
+ private @Nullable SleepIQCloudHandler getCloudHandler() {
+ Bridge bridge = getBridge();
+ if (bridge != null) {
+ return (SleepIQCloudHandler) bridge.getHandler();
}
+ return null;
}
}
<description>Username of a registered SleepIQ account owner</description>
</parameter>
<parameter name="password" type="text" required="false">
- <context>password</context>
<label>Password</label>
<description>Password of a registered SleepIQ account owner</description>
+ <context>password</context>
</parameter>
<parameter name="pollingInterval" type="integer" min="30" step="30" required="true">
<label>Polling Interval</label>
<description>Seconds between fetching values from the cloud service</description>
- <default>60</default>
+ <default>120</default>
</parameter>
</config-description>
</bridge-type>
<channel id="lastLink" typeId="lastLinkType"/>
<channel id="alertId" typeId="alertIdType"/>
<channel id="alertDetailedMessage" typeId="alertDetailedMessageType"/>
+ <channel id="firstName" typeId="firstNameType"/>
+ <channel id="sleepGoalMinutes" typeId="sleepGoalMinutesType"/>
+ <channel id="privacyMode" typeId="privacyMode"/>
+ <channel id="todaySleepIQ" typeId="todaySleepIQType"/>
+ <channel id="todayAverageHeartRate" typeId="todayAverageHeartRateType"/>
+ <channel id="todayAverageRespirationRate" typeId="todayAverageRespirationRateType"/>
+ <channel id="todayMessage" typeId="todayMessageType"/>
+ <channel id="todaySleepDurationSeconds" typeId="todaySleepDurationSecondsType"/>
+ <channel id="monthlySleepIQ" typeId="monthlySleepIQType"/>
+ <channel id="monthlyAverageHeartRate" typeId="monthlyAverageHeartRateType"/>
+ <channel id="monthlyAverageRespirationRate" typeId="monthlyAverageRespirationRateType"/>
</channels>
</channel-group-type>
<item-type>Number</item-type>
<label>Sleep Number</label>
<description>The Sleep Number setting of the chamber</description>
- <state readOnly="true"/>
+ <state readOnly="false" min="5" max="100" step="5" pattern="%d"/>
</channel-type>
<channel-type id="pressureType">
<item-type>Number</item-type>
<description>A detailed message describing an alert condition with the chamber</description>
<state readOnly="true"/>
</channel-type>
+ <channel-type id="firstNameType">
+ <item-type>String</item-type>
+ <label>First Name</label>
+ <description>The first name of the sleeper</description>
+ <state readOnly="true"/>
+ </channel-type>
+ <channel-type id="sleepGoalMinutesType">
+ <item-type>Number:Time</item-type>
+ <label>Sleep Goal</label>
+ <description>The goal for the amount of sleep per night (in minutes)</description>
+ <state readOnly="true" pattern="%d %unit%"/>
+ </channel-type>
+ <channel-type id="privacyMode">
+ <item-type>Switch</item-type>
+ <label>Privacy Mode</label>
+ <description>Enable/disable privacy mode</description>
+ <state readOnly="false"/>
+ </channel-type>
+ <channel-type id="todaySleepIQType">
+ <item-type>Number</item-type>
+ <label>Today's Sleep IQ</label>
+ <description>The Sleep Quotient for today</description>
+ <state readOnly="true" pattern="%d"/>
+ </channel-type>
+ <channel-type id="todayAverageHeartRateType">
+ <item-type>Number</item-type>
+ <label>Today's Avg Heart Rate</label>
+ <description>The average heart rate for today</description>
+ <state readOnly="true" pattern="%d"/>
+ </channel-type>
+ <channel-type id="todayAverageRespirationRateType">
+ <item-type>Number</item-type>
+ <label>Today's Avg Respiration Rate</label>
+ <description>The average respiration rate for today</description>
+ <state readOnly="true" pattern="%d"/>
+ </channel-type>
+ <channel-type id="todayMessageType">
+ <item-type>String</item-type>
+ <label>Today's Message</label>
+ <description>The description of today's sleep quality</description>
+ <state readOnly="true"/>
+ </channel-type>
+ <channel-type id="todaySleepDurationSecondsType">
+ <item-type>Number:Time</item-type>
+ <label>Today's Sleep Duration</label>
+ <description>The total duration of sleep for today in seconds</description>
+ <state readOnly="true" pattern="%d %unit%"/>
+ </channel-type>
+ <channel-type id="monthlySleepIQType">
+ <item-type>Number</item-type>
+ <label>Monthly Sleep IQ</label>
+ <description>The overall Sleep Quotient for the past month</description>
+ <state readOnly="true" pattern="%d"/>
+ </channel-type>
+ <channel-type id="monthlyAverageHeartRateType">
+ <item-type>Number</item-type>
+ <label>Monthly Avg Heart Rate</label>
+ <description>The average heart rate for the past month</description>
+ <state readOnly="true" pattern="%d"/>
+ </channel-type>
+ <channel-type id="monthlyAverageRespirationRateType">
+ <item-type>Number</item-type>
+ <label>Monthly Avg Respiration Rate</label>
+ <description>The average respiration rate for the past month</description>
+ <state readOnly="true" pattern="%d"/>
+ </channel-type>
</thing:thing-descriptions>
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.FileReader;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.BedSideStatus;
+import org.openhab.binding.sleepiq.internal.api.dto.TimeSince;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link BedSideStatusTest} tests deserialization of a bed side status object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class BedSideStatusTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ BedSideStatus bedSideStatus = new BedSideStatus().withAlertDetailedMessage("No Alert").withAlertId(0L)
+ .withInBed(false).withLastLink(new TimeSince().withDuration(3, 5, 4, 38)).withPressure(573)
+ .withSleepNumber(55);
+ assertEquals(readJson("bed-side-status.json"), gson.toJson(bedSideStatus));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("bed-side-status.json"))) {
+ BedSideStatus bedSideStatus = gson.fromJson(reader, BedSideStatus.class);
+ assertEquals("No Alert", bedSideStatus.getAlertDetailedMessage());
+ assertEquals(Long.valueOf(0L), bedSideStatus.getAlertId());
+ assertFalse(bedSideStatus.isInBed());
+ assertEquals(new TimeSince().withDuration(3, 5, 4, 38), bedSideStatus.getLastLink());
+ assertEquals(Integer.valueOf(573), bedSideStatus.getPressure());
+ assertEquals(Integer.valueOf(55), bedSideStatus.getSleepNumber());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.FileReader;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.BedSideStatus;
+import org.openhab.binding.sleepiq.internal.api.dto.BedStatus;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link BedStatusText} tests deserialization of a bed status object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class BedStatusTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ BedStatus bedStatus = new BedStatus().withBedId("-9999999999999999999")
+ .withLeftSide(new BedSideStatus().withInBed(true)).withRightSide(new BedSideStatus().withInBed(false))
+ .withStatus(1L);
+ assertEquals(readJson("bed-status.json"), gson.toJson(bedStatus));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("bed-status.json"))) {
+ BedStatus bedStatus = gson.fromJson(reader, BedStatus.class);
+ assertEquals("-9999999999999999999", bedStatus.getBedId());
+ assertEquals(Long.valueOf(1L), bedStatus.getStatus());
+
+ BedSideStatus leftSide = bedStatus.getLeftSide();
+ assertNotNull(leftSide);
+ assertTrue(leftSide.isInBed());
+
+ BedSideStatus rightSide = bedStatus.getRightSide();
+ assertNotNull(rightSide);
+ assertFalse(rightSide.isInBed());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.FileReader;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.Bed;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link BedTest} tests deserialization of a bed object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class BedTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ Bed bed = new Bed().withAccountId("-8888888888888888888").withBase("MODULAR").withBedId("-9999999999999999999")
+ .withDualSleep(true).withKidsBed(false).withMacAddress("AABBCCDDEEFF").withModel("P5").withName("Bed")
+ .withPurchaseDate(ZonedDateTime.of(2017, 2, 2, 0, 0, 1, 0, ZoneId.of("Z").normalized()))
+ .withReference("55555555555-5")
+ .withRegistrationDate(ZonedDateTime.of(2017, 2, 17, 2, 14, 10, 0, ZoneId.of("Z").normalized()))
+ .withReturnRequestStatus(0L).withSerial("").withSize("QUEEN").withSku("QP5")
+ .withSleeperLeftId("-2222222222222222222").withSleeperRightId("-1111111111111111111").withStatus(1L)
+ .withTimezone("US/Pacific").withVersion("").withZipCode("90210");
+ assertEquals(readJson("bed.json"), gson.toJson(bed));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("bed.json"))) {
+ Bed bed = gson.fromJson(reader, Bed.class);
+ assertEquals("-8888888888888888888", bed.getAccountId());
+ assertEquals("MODULAR", bed.getBase());
+ assertEquals("-9999999999999999999", bed.getBedId());
+ assertEquals(true, bed.isDualSleep());
+ assertEquals(false, bed.isKidsBed());
+ assertEquals("AABBCCDDEEFF", bed.getMacAddress());
+ assertEquals("P5", bed.getModel());
+ assertEquals("Bed", bed.getName());
+ assertEquals(ZonedDateTime.of(2017, 2, 2, 0, 0, 1, 0, ZoneId.of("Z").normalized()), bed.getPurchaseDate());
+ assertEquals("55555555555-5", bed.getReference());
+ assertEquals(ZonedDateTime.of(2017, 2, 17, 2, 14, 10, 0, ZoneId.of("Z").normalized()),
+ bed.getRegistrationDate());
+ assertEquals(Long.valueOf(0L), bed.getReturnRequestStatus());
+ assertEquals("", bed.getSerial());
+ assertEquals("QUEEN", bed.getSize());
+ assertEquals("QP5", bed.getSku());
+ assertEquals("-2222222222222222222", bed.getSleeperLeftId());
+ assertEquals("-1111111111111111111", bed.getSleeperRightId());
+ assertEquals(Long.valueOf(1L), bed.getStatus());
+ assertEquals("US/Pacific", bed.getTimezone());
+ assertEquals("", bed.getVersion());
+ assertEquals("90210", bed.getZipCode());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.FileReader;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.Bed;
+import org.openhab.binding.sleepiq.internal.api.dto.BedsResponse;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link BedsResponseTest} tests deserialization of a beds response object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class BedsResponseTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ BedsResponse bedsResponse = new BedsResponse()
+ .withBeds(Arrays.asList(new Bed().withName("Bed1"), new Bed().withName("Bed2")));
+ assertEquals(readJson("beds-response.json"), gson.toJson(bedsResponse));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("beds-response.json"))) {
+ BedsResponse bedsResponse = gson.fromJson(reader, BedsResponse.class);
+
+ List<Bed> beds = bedsResponse.getBeds();
+ assertNotNull(beds);
+ assertEquals(2, beds.size());
+ assertEquals("Bed1", beds.get(0).getName());
+ assertEquals("Bed2", beds.get(1).getName());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.FileReader;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.BedStatus;
+import org.openhab.binding.sleepiq.internal.api.dto.FamilyStatusResponse;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link FamilyStatusText} tests deserialization of a family status object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class FamilyStatusTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ FamilyStatusResponse familyStatus = new FamilyStatusResponse()
+ .withBeds(Arrays.asList(new BedStatus().withStatus(1L)));
+ assertEquals(readJson("family-status.json"), gson.toJson(familyStatus));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("family-status.json"))) {
+ FamilyStatusResponse familyStatus = gson.fromJson(reader, FamilyStatusResponse.class);
+
+ List<BedStatus> beds = familyStatus.getBeds();
+ assertNotNull(beds);
+ assertEquals(1, beds.size());
+ assertEquals(Long.valueOf(1L), beds.get(0).getStatus());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.FileReader;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.PauseModeResponse;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link PauseModeTest} tests deserialization of a pause mode object.
+ *
+ * @author Mark Hilbush - Initial contribution
+ */
+@NonNullByDefault
+public class PauseModeTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ PauseModeResponse pauseMode = new PauseModeResponse().withAccountId("-8888888888888888888")
+ .withBedId("-9999999999999999999").withPauseMode("off");
+ assertEquals(readJson("pause-mode.json"), gson.toJson(pauseMode));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("pause-mode.json"))) {
+ PauseModeResponse pauseMode = gson.fromJson(reader, PauseModeResponse.class);
+ assertEquals("-8888888888888888888", pauseMode.getAccountId());
+ assertEquals("-9999999999999999999", pauseMode.getBedId());
+ assertEquals("off", pauseMode.getPauseMode());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.FileReader;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.Sleeper;
+import org.openhab.binding.sleepiq.internal.api.enums.Side;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link SleeperTest} tests deserialization of a sleeper object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class SleeperTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ Sleeper sleeper = new Sleeper().withAccountId("-5555555555555555555").withAccountOwner(true).withActive(true)
+ .withAvatar("").withBedId("-9999999999999999999").withBirthMonth(6).withBirthYear("1970")
+ .withChild(false).withDuration("").withEmail("alice@domain.com").withEmailValidated(true)
+ .withFirstName("Alice").withHeight(64).withLastLogin("2017-02-17 20:19:36 CST").withLicenseVersion(6L)
+ .withMale(false).withSide(Side.RIGHT).withSleeperId("-1111111111111111111").withSleepGoal(450)
+ .withTimezone("US/Pacific").withUsername("alice@domain.com").withWeight(110).withZipCode("90210");
+ assertEquals(readJson("sleeper.json"), gson.toJson(sleeper));
+ }
+
+ @Test
+ public void testSerializeLastLoginNull() throws Exception {
+ Sleeper sleeper = new Sleeper().withLastLogin("null");
+ assertEquals(readJson("sleeper-lastlogin-null.json"), gson.toJson(sleeper));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("sleeper.json"))) {
+ Sleeper sleeper = gson.fromJson(reader, Sleeper.class);
+ assertEquals("-5555555555555555555", sleeper.getAccountId());
+ assertEquals(true, sleeper.isAccountOwner());
+ assertEquals(true, sleeper.isActive());
+ assertEquals("", sleeper.getAvatar());
+ assertEquals("-9999999999999999999", sleeper.getBedId());
+ assertEquals(Integer.valueOf(6), sleeper.getBirthMonth());
+ assertEquals("1970", sleeper.getBirthYear());
+ assertEquals(false, sleeper.isChild());
+ assertEquals("", sleeper.getDuration());
+ assertEquals("alice@domain.com", sleeper.getEmail());
+ assertEquals(true, sleeper.isEmailValidated());
+ assertEquals("Alice", sleeper.getFirstName());
+ assertEquals(Integer.valueOf(64), sleeper.getHeight());
+ assertEquals("2017-02-17 20:19:36 CST", sleeper.getLastLogin());
+ assertEquals(Long.valueOf(6L), sleeper.getLicenseVersion());
+ assertEquals(false, sleeper.isMale());
+ assertEquals(Side.RIGHT, sleeper.getSide());
+ assertEquals("-1111111111111111111", sleeper.getSleeperId());
+ assertEquals(Integer.valueOf(450), sleeper.getSleepGoal());
+ assertEquals("US/Pacific", sleeper.getTimezone());
+ assertEquals("alice@domain.com", sleeper.getUsername());
+ assertEquals(Integer.valueOf(110), sleeper.getWeight());
+ assertEquals("90210", sleeper.getZipCode());
+ }
+ }
+
+ @Test
+ public void testDeserializeLastLoginNull() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("sleeper-lastlogin-null.json"))) {
+ Sleeper sleeper = gson.fromJson(reader, Sleeper.class);
+ assertEquals("null", sleeper.getLastLogin());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.io.FileReader;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.api.test.AbstractTest;
+import org.openhab.binding.sleepiq.internal.api.dto.Sleeper;
+import org.openhab.binding.sleepiq.internal.api.dto.SleepersResponse;
+import org.openhab.binding.sleepiq.internal.api.impl.GsonGenerator;
+
+import com.google.gson.Gson;
+
+/**
+ * The {@link SleepersResponseTest} tests deserialization of a sleepers response object.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class SleepersResponseTest extends AbstractTest {
+ private static Gson gson = GsonGenerator.create(true);
+
+ @Test
+ public void testSerializeAllFields() throws Exception {
+ SleepersResponse sleepersResponse = new SleepersResponse()
+ .withSleepers(Arrays.asList(new Sleeper().withFirstName("Alice"), new Sleeper().withFirstName("Bob")));
+ assertEquals(readJson("sleepers-response.json"), gson.toJson(sleepersResponse));
+ }
+
+ @Test
+ public void testDeserializeAllFields() throws Exception {
+ try (FileReader reader = new FileReader(getTestDataFile("sleepers-response.json"))) {
+ SleepersResponse sleepersResponse = gson.fromJson(reader, SleepersResponse.class);
+
+ List<Sleeper> sleepers = sleepersResponse.getSleepers();
+ assertNotNull(sleepers);
+ assertEquals(2, sleepers.size());
+ assertEquals("Alice", sleepers.get(0).getFirstName());
+ assertEquals("Bob", sleepers.get(1).getFirstName());
+ }
+ }
+}
--- /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.sleepiq.api.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.time.Duration;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.sleepiq.internal.api.dto.TimeSince;
+
+/**
+ * The {@link TimeSinceText} tests TimeSince.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public class TimeSinceTest {
+ @Test
+ public void testWithDuration() {
+ assertEquals(new TimeSince().withDuration(0, 0, 0, 0).getDuration(),
+ new TimeSince().withDuration(Duration.parse("PT00H00M00S")).getDuration());
+ assertEquals(new TimeSince().withDuration(0, 2, 3, 4).getDuration(),
+ new TimeSince().withDuration(Duration.parse("PT02H03M04S")).getDuration());
+ assertEquals(new TimeSince().withDuration(0, 12, 34, 56).getDuration(),
+ new TimeSince().withDuration(Duration.parse("PT12H34M56S")).getDuration());
+ assertEquals(new TimeSince().withDuration(1, 2, 3, 4).getDuration(),
+ new TimeSince().withDuration(Duration.parse("P1DT02H03M04S")).getDuration());
+ assertEquals(new TimeSince().withDuration(12, 23, 34, 45).getDuration(),
+ new TimeSince().withDuration(Duration.parse("P12DT23H34M45S")).getDuration());
+ }
+
+ @Test
+ public void testToString() {
+ assertEquals("00:00:00", new TimeSince().withDuration(Duration.parse("PT00H00M00S")).toString());
+ assertEquals("02:03:04", new TimeSince().withDuration(Duration.parse("PT02H03M04S")).toString());
+ assertEquals("12:34:56", new TimeSince().withDuration(Duration.parse("PT12H34M56S")).toString());
+ assertEquals("1 d 02:03:04", new TimeSince().withDuration(Duration.parse("P1DT02H03M04S")).toString());
+ assertEquals("12 d 23:34:45", new TimeSince().withDuration(Duration.parse("P12DT23H34M45S")).toString());
+ }
+
+ @Test
+ public void testParse() {
+ assertEquals(Duration.parse("PT00H00M00S"), TimeSince.parse("00:00:00").getDuration());
+ assertEquals(Duration.parse("PT2H3M4S"), TimeSince.parse("02:03:04").getDuration());
+ assertEquals(Duration.parse("PT12H34M56S"), TimeSince.parse("12:34:56").getDuration());
+ assertEquals(Duration.parse("P1DT2H3M4S"), TimeSince.parse("1 d 02:03:04").getDuration());
+ assertEquals(Duration.parse("P12DT23H34M45S"), TimeSince.parse("12 d 23:34:45").getDuration());
+ }
+}
--- /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.sleepiq.api.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link AbstractTest} tests deserialization of a sleepiq API objects.
+ *
+ * @author Gregory Moyer - Initial contribution
+ */
+@NonNullByDefault
+public abstract class AbstractTest {
+ private static final String RESOURCES_PATH = "src/test/resources/";
+
+ protected File getTestDataFile(String name) {
+ return getTestDataPath(name).toFile();
+ }
+
+ @SuppressWarnings("null")
+ protected Path getTestDataPath(String name) {
+ String packageName = this.getClass().getPackage().getName();
+
+ List<String> paths = new ArrayList<>();
+ paths.addAll(Arrays.asList(packageName.split("\\.")));
+ paths.add(name);
+
+ return Paths.get(RESOURCES_PATH, paths.toArray(new String[paths.size()]));
+ }
+
+ protected String readJson(String jsonFileName) throws IOException {
+ return String.join("\n", Files.readAllLines(getTestDataPath(jsonFileName)));
+ }
+}