From: Wouter Born Date: Sun, 20 Jun 2021 17:59:46 +0000 (+0200) Subject: [nest] Add support for Smart Device Management (SDM) API (#8947) X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=6296eba14cbc2bc51fa33794ec185f0dd2da2e3c;p=openhab-addons.git [nest] Add support for Smart Device Management (SDM) API (#8947) * [nest] Add support for Smart Device Management (SDM) API * Reworks WWN implementation so that the thing types have a wwn_ prefix and the classes have a WWN prefix and reside in a 'wwn' package * Adds an SDM implementation which is also based on: https://github.com/bhigg-code/openhab-addons/tree/2.5.x/bundles/org.openhab.binding.nestdeviceaccess * Adds unit tests for (de)serialization of the SDM and Pub/Sub API requests and responses * Updates the binding documentation for the changes and additions Fixes #8664 Also-by: Brian Higginbotham Signed-off-by: Wouter Born * Fix and improve documentation Signed-off-by: Wouter Born * Always use UTF8 when decoding SDM events Signed-off-by: Wouter Born --- diff --git a/bundles/org.openhab.binding.nest/README.md b/bundles/org.openhab.binding.nest/README.md index 627b2058f9..b2857d32fd 100644 --- a/bundles/org.openhab.binding.nest/README.md +++ b/bundles/org.openhab.binding.nest/README.md @@ -1,66 +1,243 @@ # Nest Binding -The Nest binding integrates devices by [Nest](https://nest.com) using the [Nest API](https://developers.nest.com/documentation/cloud/get-started) (REST). +The Nest binding integrates devices by [Nest](https://store.google.com/us/category/connected_home?) using the [Smart Device Management](https://developers.google.com/nest/device-access/api) (SDM) API and the Works with Nest (WWN) API. -Because the Nest API runs on Nest's servers a connection with the Internet is required for sending and receiving information. -The binding uses HTTPS to connect to the Nest API using ports 443 and 9553. Make sure outbound connections to these ports are not blocked by a firewall. +To be able to use the SDM API it is required to first [register](https://developers.google.com/nest/device-access/registration) and pay a US$5 non-refundable registration fee. -> Note: This binding can only be used with Nest devices if you have an existing Nest developer account signed up for the Works with Nest (WWN) program. -New integrations using the WWN program are no longer accepted because WWN is being retired. -To keep using this binding do **NOT** migrate your Nest Account to a Google Account. -For more information see [What's happening at Nest?](https://nest.com/whats-happening/). +It is also possible to use the older WWN API with this binding. +For this you need to have the account details of a previously registered WWN API account. +Another requirement is that you have not yet migrated your Nest account to a Google account (which is irreversible). +It is no longer possible to register new WWN API accounts because the WWN API runs in maintenance mode. +See also [What's happening at Nest?](https://nest.com/whats-happening/). + +Because the SDM and WWN APIs run on servers in the cloud, a connection with the Internet is required for sending and receiving information. +The binding uses HTTPS to connect to the APIs using port 443. +When using the WWN API, the binding also connects to servers on port 9553. +So make sure outbound connections to these ports are not blocked by a firewall. ## Supported Things The table below lists the Nest binding thing types: -| Things | Description | Thing Type | -|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|----------------| -| Nest Account | An account for using the Nest REST API | account | -| Nest Cam (Indoor, IQ, Outdoor), Dropcam | A Nest Cam registered with your account | camera | -| Nest Protect | The smoke detector/Nest Protect for the account | smoke_detector | -| Structure | The Nest structure defines the house the account has setup on Nest. You will only have more than one structure if you have more than one house | structure | -| Nest Thermostat (E) | A Thermostat to control the various aspects of the house's HVAC system | thermostat | - -## Authorization - -The Nest API uses OAuth for authorization. -Therefore the binding needs some authorization parameters before it can access your Nest account via the Nest API. - -To get these authorization parameters you first need to sign up as a [Nest Developer](https://developer.nest.com) and [register a new Product](https://developer.nest.com/products/new) (free and instant). - -While registering a new Product (on the Product Details page) make sure to: - -* Leave both "OAuth Redirect URI" fields empty to enable PIN-based authorization. -* Grant all the permissions you intend to use. When in doubt, enable the permission because the binding needs to be reauthorized when permissions change at a later time. - -After creating the Product, your browser shows the Product Overview page. -This page contains the **Product ID** and **Product Secret** authorization parameters that are used by the binding. -Take note of both parameters or keep this page open in a browser tab. -Now copy and paste the "Authorization URL" in a new browser tab. -Accept the permissions and you will be presented the **Pincode** authorization parameter that is also used by the binding. - -You can return to the Product Overview page at a later time by opening the [Products](https://console.developers.nest.com/products) page and selecting your Product. +| Things | Description | SDM Thing Type | WWN Thing Type | +|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|----------------|--------------------| +| Nest Account (SDM, WWN) | An account for using the Nest (SDM/WWN) REST API | sdm_account | wwn_account | +| Nest Cam (Indoor, IQ, Outdoor), Dropcam | A Nest Cam registered with your account | sdm_camera | wwn_camera | +| Nest Hello Doorbell | A Nest Doorbell registered with your account | sdm_doorbell | wwn_camera | +| Nest Hub (Max) | A Nest Display registered with your account | sdm_display | wwn_camera | +| Nest Protect | The smoke detector/Nest Protect for the account | | wwn_smoke_detector | +| Nest Thermostat (E) | A Thermostat to control the various aspects of the house's HVAC system | sdm_thermostat | wwn_thermostat | +| Structure | The Nest structure defines the house the account has setup on Nest. You will only have more than one structure if you have more than one house | | wwn_structure | + +The SDM API currently does not support Nest Protect devices. +There are no structure Things when using the SDM API, because the SDM API does not support setting the Home/Away status like the WWN API does. + +To use one of the Nest APIs, add the corresponding Account Thing using the UI and configure the required parameters. +After configuring an Account Thing, you can use it to discover the connected devices which are then added the Inbox. + +## SDM Account Configuration + +### Google Account Requirement + +To be able to use the SDM API it is required that you use a Google Account with your Nest devices. +If you still use the WWN API, you can no longer use the WWN API after migrating to a Google Account. +So if you have not yet migrated your account, check that all the functionality you require is provided by the SDM API and SDM Things in the binding. +Most notably, there is no support for the Nest Protect in the SDM API and you cannot change your Home/Away status. +To migrate to a Google account, follow the migration steps in the [Nest accounts FAQ](https://support.google.com/googlenest/answer/9297676?co=GENIE.Platform%3DiOS&hl=en&oco=0#accountmigration&accountmigration1&#accountmigration2&#accountmigration3&zippy=%2Chow-do-i-migrate-my-account) + +### SDM Configuration Parameters + +These parameters configure which SDM project is accessed using the SDM API and configure the OAuth 2.0 client details used for accessing the project. + +First a SDM project needs to be created and configured: + +1. Register for device access by clicking the "Go to Device Access Console" button and follow the instructions on the [Device Access Registration](https://developers.google.com/nest/device-access/registration) page. +1. Create a new SDM project on the [Projects](https://console.nest.google.com/device-access/project-list) page + 1. Give your project a name so it is easily recognizable + 1. "Skip" entering the OAuth client ID for now + 1. If you want to download camera images using the binding, it is required to "Enable" events. + Enabling events also allows for faster thermostat state updates. + The binding only uses events when the Pub/Sub configuration parameters of the Nest SDM Account Thing are also configured. + 1. After clicking the "Create project" button, the SDM project details of the created project show +1. Copy and save the **Project ID** at the top of the page (e.g. `585de72e-968c-435c-b16a-31d1d3f76833`) somewhere + +Now an OAuth 2.0 client is created and configured for using the SDM API by the binding: + +1. Configure the "Publishing status" of your Google Cloud Platform to "Production" ([APIs & Services > OAuth consent screen](https://console.cloud.google.com/apis/credentials/consent)) so the OAuth 2.0 tokens do not expire after 2 weeks +1. Create a new client on the "Credentials" page ([APIs & Services > Credentials](https://console.cloud.google.com/apis/credentials)): + 1. Click the "Create Credentials" button at the top of the page + 1. Choose "OAuth client ID" + 1. As "Application type" choose "TVs and Limited Input devices" + 1. Give it a name so you can remember what it is used for (e.g. `Nest Binding SDM`) + 1. Click "Create" to create the client + 1. Copy and save the generated **Client ID** (e.g. `1046297811237-3f5sj4ccfubit0fum027ral82jgffsd1.apps.googleusercontent.com`) and **Client Secret** (e.g. `726kcU-d1W4RXxEJA79oZ0oG`) somewhere +1. Configure the SDM project to use the created client: + 1. Go the the SDM [Projects](https://console.nest.google.com/device-access/project-list) page + 1. Click on your SDM Project to show its details + 1. Scroll to "Project Info > OAuth client ID" and open the options menu (3 stacked dots) at the end of the line + 1. Select the "Edit" option + 1. Copy/paste the saved OAuth 2.0 Client ID here (e.g. `1046297811237-3f5sj4ccfubit0fum027ral82jgffsd1.apps.googleusercontent.com`) + 1. Click the "Save" button at the end of the line to update the project + +Finally, an SDM Account Thing can be created to access the SDM project using the SDM API with the created client: + +1. Create a new "Nest SDM Account" Thing in openHAB +1. Copy/paste the saved SDM **Project ID** to SDM group parameter in the SDM Account Thing configuration parameters (e.g. `585de72e-968c-435c-b16a-31d1d3f76833`) +1. Copy/paste the saved OAuth 2.0 **Client ID** to SDM group parameter (e.g. `1046297811237-3f5sj4ccfubit0fum027ral82jgffsd1.apps.googleusercontent.com`) +1. Copy/paste the saved OAuth 2.0 **Client Secret** to SDM group parameter (e.g. `726kcU-d1W4RXxEJA79oZ0oG`) +1. Create an authorization code for the binding: + 1. Replace the **Project ID** and **Client ID** in the URL below with your SDM Project ID and SDM OAuth 2.0 Client ID and open the URL in a new browser tab: + + `https://nestservices.google.com/partnerconnections/{{ProjectID}}/auth?redirect_uri=urn:ietf:wg:oauth:2.0:oob&access_type=offline&prompt=consent&client_id={{ClientID}}&response_type=code&scope=https://www.googleapis.com/auth/sdm.service` + + For the example values used so far this is: + + `https://nestservices.google.com/partnerconnections/585de72e-968c-435c-b16a-31d1d3f76833/auth?redirect_uri=urn:ietf:wg:oauth:2.0:oob&access_type=offline&prompt=consent&client_id=1046297811237-3f5sj4ccfubit0fum027ral82jgffsd1.apps.googleusercontent.com&response_type=code&scope=https://www.googleapis.com/auth/sdm.service` + 1. Enable all the permissions you want to use with the binding and click "Next" to continue + 1. Login using your Google account when prompted + 1. On the "Google hasn't verified this app" page, click on "Advanced" + 1. Then click on "Go to ... (advanced)" + 1. Now "Allow" the SDM permissions and confirm your choices again by clicking "Allow" + 1. Next the "Sign in" page will show the **Authorization Code** + 1. Copy/paste the **Authorization Code** to the SDM group parameter in the openHAB Nest SDM Account Thing configuration +1. All required SDM Account Thing configuration parameters have now been entered so create it by clicking "Create Thing". + +The SDM Account Thing should now be ONLINE and have as status description "Using periodic refresh". +It should also be possible to use the configured account to discover your Nest devices via the Inbox. + +You can monitor the SDM API using the Google Cloud Platform Console via [API & Services > Smart Device Management API](https://console.cloud.google.com/apis/api/smartdevicemanagement.googleapis.com/overview). + +If you've made it this far, it should be easy to edit the SDM Account Thing again and update it so it can also use SDM Pub/Sub events. :-) + +### Pub/Sub Configuration Parameters + +After configuring the SDM configuration parameters, a SDM Account Thing can be updated so it can listen to SDM events using Pub/Sub. +This is required if you want to download camera images using the binding or to get faster thermostat state updates. + +Enable Pub/Sub events in your SDM project: + +1. Open your SDM project details using the [Projects](https://console.nest.google.com/device-access/project-list) page +1. Scroll to "Project Info > Pub/Sub topic" and check if it is set to "Enabled" +1. If it is set to "Disabled", enable events: + 1. Open the options menu (3 stacked dots) at the end of the line + 1. Select the "Edit" option + 1. Check the "Enable events" option + 1. Click the "Save" button at the end of the line to update the project + +Lookup your Google Cloud Platform (GCP) Project ID: + +1. Open the [IAM & Admin > Settings](https://console.cloud.google.com/iam-admin/settings) +1. Copy and save the GCP **Project ID** (e.g. `openhab-12345`) + +Next an OAuth 2.0 client is created which is used to create a Pub/Sub subscription for listening to SDM events by the binding: + +1. Open the "Credentials" page ([APIs & Services > Credentials](https://console.cloud.google.com/apis/credentials)): +1. Click the "Create Credentials" button at the top of the page +1. Choose "OAuth client ID" +1. As "Application type" choose "TVs and Limited Input devices" +1. Give it a name so you can remember what it is used for (e.g. `Nest Binding Pub/Sub`) +1. Click "Create" to create the client +1. Copy and save the generated **Client ID** (e.g. `1046297811237-lg27h26kln6r1nbg54jpg6nfjg6h4b3n.apps.googleusercontent.com`) and **Client Secret** (e.g. `1-k78-XcHhp_gdZF-I6JaIHp`) somewhere + +Finally, the existing SDM Account Thing can be updated so it can subscribe to SDM events: + +1. Open the configuration details of your existing "Nest SDM Account" Thing in openHAB +1. Copy/paste the saved GCP **Project ID** to Pub/Sub group parameter (e.g. `openhab-123`) +1. Enter a name in **Subscription ID** that uniquely identifies the Pub/Sub subscription used by the binding + + > Must be 3-255 characters, start with a letter, and contain only the following characters: letters, numbers, dashes (-), periods (.), underscores (_), tildes (~), percents (%) or plus signs (+). Cannot start with goog. +1. Copy/paste the saved OAuth 2.0 **Client ID** to Pub/Sub group parameter (e.g. `1046297811237-lg27h26kln6r1nbg54jpg6nfjg6h4b3n.apps.googleusercontent.com`) +1. Copy/paste the saved OAuth 2.0 **Client Secret** to Pub/Sub group parameter (e.g. `1-k78-XcHhp_gdZF-I6JaIHp`) +1. Create an authorization code for the binding: + 1. Replace the **Client ID** in the URL below with your Pub/Sub OAuth 2.0 Client ID and open the URL in a new browser tab: + + `https://accounts.google.com/o/oauth2/auth?client_id={{ClientID}}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/pubsub` + + For the example client this is: + + `https://accounts.google.com/o/oauth2/auth?client_id=1046297811237-lg27h26kln6r1nbg54jpg6nfjg6h4b3n.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/pubsub` + 1. Login using your Google account when prompted + 1. On the "Google hasn't verified this app" page, click on "Advanced" + 1. Then click on "Go to ... (advanced)" + 1. Now "Allow" the Pub/Sub permissions and confirm your choices again by clicking "Allow" + 1. Next the "Sign in" page will show the **Authorization Code** + 1. Copy/paste the **Authorization Code** to the Pub/Sub group parameter in the openHAB Nest SDM Account Thing configuration +1. All required Pub/Sub Account Thing configuration parameters have now been entered so click "Save" to update the SDM Account Thing configuration. + +The SDM Account Thing should now be ONLINE and have as status description "Using periodic refresh and Pub/Sub". + +The created subscription can also be monitored using the Google Cloud Platform Console via [Pub/Sub > Subscriptions](https://console.cloud.google.com/cloudpubsub/subscription/list). + +## SDM Device Configuration + +| Configuration Parameter | Required | Default | Description | +|-------------------------|----------|---------|---------------------------------------------------------------------------| +| deviceId | X | | Identifies the device in the SDM API | +| refreshInterval | | 300 | This is refresh interval in seconds to update the Nest device information | + +Decreasing the `refreshInterval` may cause issues when you have a lot of devices connected because it may cause API rate limits to be exceeded. +You may want to decrease the `refreshInterval` for a Thermostat if Pub/Sub events have not been configured to provide state updating. + +## WWN Account Configuration + +To configure the binding to use the WWN API, add a new "Nest WWN Account" Thing in the UI and enter the **Product ID**, **Product Secret** and **Access Token** of an existing WWN account as configuration parameters. +It is no longer possible to register new WWN accounts with Nest because the WWN API runs in maintenance mode. ## Discovery -The binding will discover all Nest Things from your account when you add and configure a "Nest Account" Thing. -See the Authorization paragraph above for details on how to obtain the Product ID, Product Secret and Pincode configuration parameters. - -Once the binding has successfully authorized with the Nest API, it obtains an Access Token using the Pincode. -The configured Pincode is cleared because it can only be used once. -The obtained Access Token is saved as an advanced configuration parameter of the "Nest Account". - -You can reuse an Access Token for authorization but not the Pincode. -A new Pincode can again be generated via the "Authorization URL" (see Authorization paragraph). +The binding will discover all Nest Things from your account when you add and configure a Nest SDM or WWN Account Thing. ## Channels -### Account Channels - -The account Thing Type does not have any channels. - -### Camera Channels +### SDM/WWN Account Channels + +The account Thing Types do not have any channels. + +### SDM Camera/Display/Doorbell Channels + +The state of these channels is based on Pub/Sub events sent by the SDM API. +So make sure the Pub/Sub account details are properly configured in the `sdm_account`. + +| Channel Type ID | Item Type | Description | Read Write | +|----------------------------------|-----------|-----------------------------------------------------|:----------:| +| chime_event#image | Image | Static image based on a chime event | R | +| chime_event#timestamp | DateTime | The last time that the door chime was pressed | R | +| live_stream#current_token | String | Live stream current token value | R | +| live_stream#expiration_timestamp | DateTime | Live stream token expiration time | R | +| live_stream#extension_token | String | Live stream token extension value | R | +| live_stream#url | String | The RTSP video stream URL for the most recent event | R | +| motion_event#image | Image | Static image based on a motion event | R | +| motion_event#timestamp | DateTime | The last time that motion was detected | R | +| person_event#image | Image | Static image based on a person event | R | +| person_event#timestamp | DateTime | The last time that a person was detected | R | +| sound_event#image | Image | Static image based on a sound event | R | +| sound_event#timestamp | DateTime | The last time that a sound was detected | R | + +The `chime_event` group channels only exist for doorbell Things. +Each image channel has the `imageWidth` and `imageHeight` configuration parameters that can be used for configuring the image size in pixels. +The maximum camera resolution is listed as `maxImageResolution` property in the Thing properties. + +### SDM Thermostat Channels + +| Channel Type ID | Item Type | Description | Read Write | +|---------------------|----------------------|------------------------------------------------------------------------|:----------:| +| ambient_humidity | Number:Dimensionless | Lists the current ambient humidity percentage from the thermostat | R | +| ambient_temperature | Number:Temperature | Lists the current ambient temperature from the thermostat | R | +| current_eco_mode | String | Lists the current eco mode from the thermostat (OFF, MANUAL_ECO) | R/W | +| current_mode | String | Lists the current mode from the thermostat (OFF, HEAT, COOL, HEATCOOL) | R/W | +| fan_timer_mode | Switch | Lists the current fan timer mode | R/W | +| fan_timer_timeout | DateTime | Timestamp at which timer mode turns OFF | R/W | +| hvac_status | String | Provides the thermostat HVAC Status (OFF, HEATING, COOLING) | R | +| maximum_temperature | Number:Temperature | Lists the maximum temperature setting from the thermostat | R/W | +| minimum_temperature | Number:Temperature | Lists the target temperature setting from the thermostat | R/W | +| target_temperature | Number:Temperature | Lists the target temperature setting from the thermostat | R/W | +| temperature_cool | Number:Temperature | Lists the heat temperature Setting from the thermostat | R | +| temperature_heat | Number:Temperature | Lists the heat temperature setting from the thermostat | R | + +The `fan_timer_mode` channel has a `fanTimerDuration` configuration parameter that can be used for configuring how long the fan is ON before it is switched OFF (1s to 43200s). +Similarly, when a DateTime command is sent to the `fan_timer_timeout` channel, the fan timer is switched ON and runs until the timestamp in the command (min now+1s, max now+43200s). + +### WWN Camera Channels **Camera group channels** @@ -96,7 +273,7 @@ Information about the last camera event (requires Nest Aware subscription). | urls_expire_time | DateTime | Timestamp when the camera event URLs expire | R | | web_url | String | The web URL for the camera event, allows you to see the camera event in a web page | R | -### Smoke Detector Channels +### WWN Smoke Detector Channels | Channel Type ID | Item Type | Description | Read Write | |-----------------------|-----------|-----------------------------------------------------------------------------------|:----------:| @@ -108,7 +285,7 @@ Information about the last camera event (requires Nest Aware subscription). | smoke_alarm_state | String | The smoke alarm state of the Nest Protect (OK, EMERGENCY, WARNING) | R | | ui_color_state | String | The current color of the ring on the smoke detector (GRAY, GREEN, YELLOW, RED) | R | -### Structure Channels +### WWN Structure Channels | Channel Type ID | Item Type | Description | Read Write | |------------------------------|-----------|--------------------------------------------------------------------------------------------------------|:----------:| @@ -124,7 +301,7 @@ Information about the last camera event (requires Nest Aware subscription). | smoke_alarm_state | String | Smoke alarm state (OK, EMERGENCY, WARNING) | R | | time_zone | String | The time zone for the structure ([IANA time zone format](https://www.iana.org/time-zones)) | R | -### Thermostat Channels +### WWN Thermostat Channels | Channel Type ID | Item Type | Description | Read Write | |-----------------------------|----------------------|----------------------------------------------------------------------------------------|:----------:| @@ -165,94 +342,144 @@ The Nest API applies the following rounding: You can use the discovery functionality of the binding to obtain the deviceId and structureId values for defining Nest things in files. -Another way to get the deviceId and structureId values is by querying the Nest API yourself. First [obtain an Access Token](https://developers.nest.com/documentation/cloud/sample-code-auth) (or use the Access Token obtained by the binding). -Then use it with one of the [API Read Examples](https://developers.nest.com/documentation/cloud/how-to-read-data). - -### demo.things: +### sdm-demo.things ``` -Bridge nest:account:demo_account [ productId="8fdf9885-ca07-4252-1aa3-f3d5ca9589e0", productSecret="QITLR3iyUlWaj9dbvCxsCKp4f", accessToken="c.6rse1xtRk2UANErcY0XazaqPHgbvSSB6owOrbZrZ6IXrmqhsr9QTmcfaiLX1l0ULvlI5xLp01xmKeiojHqozLQbNM8yfITj1LSdK28zsUft1aKKH2mDlOeoqZKBdVIsxyZk4orH0AvKEZ5aY" ] { - camera fish_cam [ deviceId="qw0NNE8ruxA9AGJkTaFH3KeUiJaONWKiH9Gh3RwwhHClonIexTtufQ" ] - smoke_detector hallway_smoke [ deviceId="Tzvibaa3lLKnHpvpi9OQeCI_z5rfkBAV" ] - structure home [ structureId="20wKjydArmMV3kOluTA7JRcZg8HKBzTR-G_2nRXuIN1Bd6laGLOJQw" ] - thermostat living_thermostat [ deviceId="ZqAKzSv6TO6PjBnOCXf9LSI_z5rfkBAV" ] +Bridge nest:sdm_account:demo_sdm_account [ sdmProjectId="585de72e-968c-435c-b16a-31d1d3f76833", sdmClientId="1046297811237-3f5sj4ccfubit0fum027ral82jgffsd1.apps.googleusercontent.com", sdmClientSecret="726kcU-d1W4RXxEJA79oZ0oG", sdmAuthorizationCode="xkkY3qYtfZCzaXCcPxpOELUW8EhgiSMD3n9jmzJ3m0yerkQpVRdj5vqWRjMSIG", pubsubProjectId="openhab-12345", pubsubSubscriptionId="nest-sdm-events", pubsubClientId="1046297811237-lg27h26kln6r1nbg54jpg6nfjg6h4b3n.apps.googleusercontent.com", pubsubClientSecret="1-k78-XcHhp_gdZF-I6JaIHp", pubsubAuthorizationCode="tASfQq7gn6sfbUSbwRufbMI0BYDzh1d7MBG2G7vdZpbhjmZfwDp5MkeaX0iMxn" ] { + Thing sdm_camera fish_cam [ deviceId="AVPHwTQCAhersqmQ3IXwyqSX-XyuVZXoiNSNPeHdIMKgYpYZolNP4S9LS5QDF2LeuM3BQcpBh_fOEZYxkeH6eoQdWEELqi" ] { + Channels: + Image : motion_event#image [ imageHeight=1080 ] + Image : person_event#image [ imageWidth=1920 ] + Image : sound_event#image [ imageHeight=1080 ] + } + Thing sdm_doorbell front_door [ deviceId="AVPHws4JWeIzZlru3DSxXoKnIgPntKpzax7a1Zwms8H0-HaRet2pTdTCPOTBZ74YDzYqq7w6XpEPwOTkBXtf4KCJ4nq9hq" ] { + Channels: + Image : chime_event#image [ imageWidth=1920 ] + } + Thing sdm_display kitchen_hub [ deviceId="AVPHw64dWG5CcAJdDNzBbHWgu91l4v8WA4CsJqgtrvMS3QrbDnurB0_WzZEwpcWaw8Y9rLEQXW0avEwCjTd40Gmia6ussU" ] + Thing sdm_thermostat living_thermostat [ deviceId="AVPHwQum_bx9LmiRfv6jv5qPcKho0vHx2HqqMUvXP3TD-TTDCJebbzkegpRMozU5t7GSeTQIzxdH2LYDsZO8RClcGj7CCT", refreshInterval=180 ] { + Channels: + Image : fan_timer_mode [ fanTimerDuration=7200 ] + } } ``` -### demo.items: +### sdm-demo.items + +``` +/* SDM Doorbell */ +Image Doorbell_Chime_Image "Chime Image" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:chime_event#image" } +DateTime Doorbell_Chime_Timestamp "Chime Timestamp [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:chime_event#timestamp" } +String Doorbell_Stream_Token "Stream Token [%s]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:live_stream#current_token" } +DateTime Doorbell_Stream_Timestamp "Stream Timestamp [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:live_stream#expiration_timestamp" } +String Doorbell_Stream_Ext_Token "Stream Extension Token [%s]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:live_stream#extension_token" } +String Doorbell_Stream_URL "Stream Extension URL [%s]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:live_stream#url" } +Image Doorbell_Motion_Image "Motion Image" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:motion_event#image" } +DateTime Doorbell_Motion_Timestamp "Motion Timestamp [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:motion_event#timestamp" } +Image Doorbell_Person_Image "Person Image" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:person_event#image" } +DateTime Doorbell_Person_Timestamp "Person Timestamp [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:person_event#timestamp" } +Image Doorbell_Sound_Image "Sound Image" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:sound_event#image" } +DateTime Doorbell_Sound_Timestamp "Sound Timestamp [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:sdm_doorbell:demo_sdm_account:front_door:sound_event#timestamp" } + +/* SDM Thermostat */ +Number:Dimensionless Thermostat_Amb_Humidity "Ambient Humidity [%.1f %unit%]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:ambient_humidity" } +Number:Temperature Thermostat_Amb_Temperature "Ambient Temperature [%.1f %unit%]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:ambient_temperature" } +String Thermostat_Current_Eco_Mode "Current Eco Mode [%s]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:current_eco_mode" } +String Thermostat_Current_Mode "Current Mode [%s]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:current_mode" } +Switch Thermostat_Fan_Timer_Mode "Fan Timer Mode" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:fan_timer_mode" } +DateTime Thermostat_Fan_Timer_Timeout "Fan Timer Timeout [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:fan_timer_timeout" } +String Thermostat_HVAC_Status "HVAC Status [%s]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:hvac_status" } +Number:Temperature Thermostat_Max_Temperature "Max Temperature [%.1f %unit%]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:maximum_temperature" } +Number:Temperature Thermostat_Min_Temperature "Min Temperature [%.1f %unit%]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:minimum_temperature" } +Number:Temperature Thermostat_Target_temperature "Target Temperature [%.1f %unit%]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:target_temperature" } +Number:Temperature Thermostat_Temperature_Cool "Temperature Cool [%.1f %unit%]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:temperature_cool" } +Number:Temperature Thermostat_Temperature_Heat "Temperature Heat [%.1f %unit%]" { channel="nest:sdm_thermostat:demo_sdm_account:living_thermostat:temperature_heat" } +``` + +### wwn-demo.things + +``` +Bridge nest:wwn_account:demo_wwn_account [ productId="8fdf9885-ca07-4252-1aa3-f3d5ca9589e0", productSecret="QITLR3iyUlWaj9dbvCxsCKp4f", accessToken="c.6rse1xtRk2UANErcY0XazaqPHgbvSSB6owOrbZrZ6IXrmqhsr9QTmcfaiLX1l0ULvlI5xLp01xmKeiojHqozLQbNM8yfITj1LSdK28zsUft1aKKH2mDlOeoqZKBdVIsxyZk4orH0AvKEZ5aY" ] { + Thing wwn_camera fish_cam [ deviceId="qw0NNE8ruxA9AGJkTaFH3KeUiJaONWKiH9Gh3RwwhHClonIexTtufQ" ] + Thing wwn_smoke_detector hallway_smoke [ deviceId="Tzvibaa3lLKnHpvpi9OQeCI_z5rfkBAV" ] + Thing wwn_structure home [ structureId="20wKjydArmMV3kOluTA7JRcZg8HKBzTR-G_2nRXuIN1Bd6laGLOJQw" ] + Thing wwn_thermostat living_thermostat [ deviceId="ZqAKzSv6TO6PjBnOCXf9LSI_z5rfkBAV" ] +} +``` +### wwn-demo.items ``` -/* Camera */ -String Cam_App_URL "App URL [%s]" { channel="nest:camera:demo_account:fish_cam:camera#app_url" } -Switch Cam_Audio_Input_Enabled "Audio Input Enabled" { channel="nest:camera:demo_account:fish_cam:camera#audio_input_enabled" } -DateTime Cam_Last_Online_Change "Last Online Change [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:camera:demo_account:fish_cam:camera#last_online_change" } -String Cam_Snapshot_URL "Snapshot URL [%s]" { channel="nest:camera:demo_account:fish_cam:camera#snapshot_url" } -Switch Cam_Streaming "Streaming" { channel="nest:camera:demo_account:fish_cam:camera#streaming" } -Switch Cam_Public_Share_Enabled "Public Share Enabled" { channel="nest:camera:demo_account:fish_cam:camera#public_share_enabled" } -String Cam_Public_Share_URL "Public Share URL [%s]" { channel="nest:camera:demo_account:fish_cam:camera#public_share_url" } -Switch Cam_Video_History_Enabled "Video History Enabled" { channel="nest:camera:demo_account:fish_cam:camera#video_history_enabled" } -String Cam_Web_URL "Web URL [%s]" { channel="nest:camera:demo_account:fish_cam:camera#web_url" } -String Cam_LE_Activity_Zones "Last Event Activity Zones [%s]" { channel="nest:camera:demo_account:fish_cam:last_event#activity_zones" } -String Cam_LE_Animated_Image_URL "Last Event Animated Image URL [%s]" { channel="nest:camera:demo_account:fish_cam:last_event#animated_image_url" } -String Cam_LE_App_URL "Last Event App URL [%s]" { channel="nest:camera:demo_account:fish_cam:last_event#app_url" } -DateTime Cam_LE_End_Time "Last Event End Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:camera:demo_account:fish_cam:last_event#end_time" } -Switch Cam_LE_Has_Motion "Last Event Has Motion" { channel="nest:camera:demo_account:fish_cam:last_event#has_motion" } -Switch Cam_LE_Has_Person "Last Event Has Person" { channel="nest:camera:demo_account:fish_cam:last_event#has_person" } -Switch Cam_LE_Has_Sound "Last Event Has Sound" { channel="nest:camera:demo_account:fish_cam:last_event#has_sound" } -String Cam_LE_Image_URL "Last Event Image URL [%s]" { channel="nest:camera:demo_account:fish_cam:last_event#image_url" } -DateTime Cam_LE_Start_Time "Last Event Start Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:camera:demo_account:fish_cam:last_event#start_time" } -DateTime Cam_LE_URLs_Expire_Time "Last Event URLs Expire Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:camera:demo_account:fish_cam:last_event#urls_expire_time" } -String Cam_LE_Web_URL "Last Event Web URL [%s]" { channel="nest:camera:demo_account:fish_cam:last_event#web_url" } - -/* Smoke Detector */ -String Smoke_CO_Alarm "CO Alarm [%s]" { channel="nest:smoke_detector:demo_account:hallway_smoke:co_alarm_state" } -Switch Smoke_Battery_Low "Battery Low" { channel="nest:smoke_detector:demo_account:hallway_smoke:low_battery" } -Switch Smoke_Manual_Test "Manual Test" { channel="nest:smoke_detector:demo_account:hallway_smoke:manual_test_active" } -DateTime Smoke_Last_Connection "Last Connection [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:smoke_detector:demo_account:hallway_smoke:last_connection" } -DateTime Smoke_Last_Manual_Test "Last Manual Test [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:smoke_detector:demo_account:hallway_smoke:last_manual_test_time" } -String Smoke_Smoke_Alarm "Smoke Alarm [%s]" { channel="nest:smoke_detector:demo_account:hallway_smoke:smoke_alarm_state" } -String Smoke_UI_Color "UI Color [%s]" { channel="nest:smoke_detector:demo_account:hallway_smoke:ui_color_state" } - -/* Thermostat */ -Switch Thermostat_Can_Cool "Can Cool" { channel="nest:thermostat:demo_account:living_thermostat:can_cool" } -Switch Thermostat_Can_Heat "Can Heat" { channel="nest:thermostat:demo_account:living_thermostat:can_heat" } -Number:Temperature Therm_EMaxSP "Eco Max Set Point [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:eco_max_set_point" } -Number:Temperature Therm_EMinSP "Eco Min Set Point [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:eco_min_set_point" } -Switch Thermostat_FT_Active "Fan Timer Active" { channel="nest:thermostat:demo_account:living_thermostat:fan_timer_active" } -Number:Time Thermostat_FT_Duration "Fan Timer Duration [%d %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:fan_timer_duration" } -DateTime Thermostat_FT_Timeout "Fan Timer Timeout [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:thermostat:demo_account:living_thermostat:fan_timer_timeout" } -Switch Thermostat_Has_Fan "Has Fan" { channel="nest:thermostat:demo_account:living_thermostat:has_fan" } -Switch Thermostat_Has_Leaf "Has Leaf" { channel="nest:thermostat:demo_account:living_thermostat:has_leaf" } -Number:Dimensionless Therm_Hum "Humidity [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:humidity" } -DateTime Thermostat_Last_Conn "Last Connection [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:thermostat:demo_account:living_thermostat:last_connection" } -Switch Thermostat_Locked "Locked" { channel="nest:thermostat:demo_account:living_thermostat:locked" } -Number:Temperature Therm_LMaxSP "Locked Max Set Point [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:locked_max_set_point" } -Number:Temperature Therm_LMinSP "Locked Min Set Point [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:locked_min_set_point" } -Number:Temperature Therm_Max_SP "Max Set Point [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:max_set_point" } -Number:Temperature Therm_Min_SP "Min Set Point [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:min_set_point" } -String Thermostat_Mode "Mode [%s]" { channel="nest:thermostat:demo_account:living_thermostat:mode" } -String Thermostat_Previous_Mode "Previous Mode [%s]" { channel="nest:thermostat:demo_account:living_thermostat:previous_mode" } -String Thermostat_State "State [%s]" { channel="nest:thermostat:demo_account:living_thermostat:state" } -Number:Temperature Thermostat_SP "Set Point [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:set_point" } -Switch Thermostat_Sunlight_CA "Sunlight Correction Active" { channel="nest:thermostat:demo_account:living_thermostat:sunlight_correction_active" } -Switch Thermostat_Sunlight_CE "Sunlight Correction Enabled" { channel="nest:thermostat:demo_account:living_thermostat:sunlight_correction_enabled" } -Number:Temperature Therm_Temp "Temperature [%.1f %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:temperature" } -Number:Time Therm_Time_To_Target "Time To Target [%d %unit%]" { channel="nest:thermostat:demo_account:living_thermostat:time_to_target" } -Switch Thermostat_Using_Em_Heat "Using Emergency Heat" { channel="nest:thermostat:demo_account:living_thermostat:using_emergency_heat" } - -/* Structure */ -String Home_Away "Away [%s]" { channel="nest:structure:demo_account:home:away" } -String Home_Country_Code "Country Code [%s]" { channel="nest:structure:demo_account:home:country_code" } -String Home_CO_Alarm_State "CO Alarm State [%s]" { channel="nest:structure:demo_account:home:co_alarm_state" } -DateTime Home_ETA "ETA [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:structure:demo_account:home:eta_begin" } -DateTime Home_PP_End_Time "PP End Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:structure:demo_account:home:peak_period_end_time" } -DateTime Home_PP_Start_Time "PP Start Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:structure:demo_account:home:peak_period_start_time" } -String Home_Postal_Code "Postal Code [%s]" { channel="nest:structure:demo_account:home:postal_code" } -Switch Home_Rush_Hour_Rewards "Rush Hour Rewards" { channel="nest:structure:demo_account:home:rush_hour_rewards_enrollment" } -String Home_Security_State "Security State [%s]" { channel="nest:structure:demo_account:home:security_state" } -String Home_Smoke_Alarm_State "Smoke Alarm State [%s]" { channel="nest:structure:demo_account:home:smoke_alarm_state" } -String Home_Time_Zone "Time Zone [%s]" { channel="nest:structure:demo_account:home:time_zone" } +/* WWN Camera */ +String Cam_App_URL "App URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#app_url" } +Switch Cam_Audio_Input_Enabled "Audio Input Enabled" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#audio_input_enabled" } +DateTime Cam_Last_Online_Change "Last Online Change [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#last_online_change" } +String Cam_Snapshot_URL "Snapshot URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#snapshot_url" } +Switch Cam_Streaming "Streaming" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#streaming" } +Switch Cam_Public_Share_Enabled "Public Share Enabled" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#public_share_enabled" } +String Cam_Public_Share_URL "Public Share URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#public_share_url" } +Switch Cam_Video_History_Enabled "Video History Enabled" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#video_history_enabled" } +String Cam_Web_URL "Web URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:camera#web_url" } +String Cam_LE_Activity_Zones "Last Event Activity Zones [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#activity_zones" } +String Cam_LE_Animated_Image_URL "Last Event Animated Image URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#animated_image_url" } +String Cam_LE_App_URL "Last Event App URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#app_url" } +DateTime Cam_LE_End_Time "Last Event End Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#end_time" } +Switch Cam_LE_Has_Motion "Last Event Has Motion" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#has_motion" } +Switch Cam_LE_Has_Person "Last Event Has Person" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#has_person" } +Switch Cam_LE_Has_Sound "Last Event Has Sound" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#has_sound" } +String Cam_LE_Image_URL "Last Event Image URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#image_url" } +DateTime Cam_LE_Start_Time "Last Event Start Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#start_time" } +DateTime Cam_LE_URLs_Expire_Time "Last Event URLs Expire Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#urls_expire_time" } +String Cam_LE_Web_URL "Last Event Web URL [%s]" { channel="nest:wwn_camera:demo_wwn_account:fish_cam:last_event#web_url" } + +/* WWN Smoke Detector */ +String Smoke_CO_Alarm "CO Alarm [%s]" { channel="nest:wwn_smoke_detector:demo_wwn_account:hallway_smoke:co_alarm_state" } +Switch Smoke_Battery_Low "Battery Low" { channel="nest:wwn_smoke_detector:demo_wwn_account:hallway_smoke:low_battery" } +Switch Smoke_Manual_Test "Manual Test" { channel="nest:wwn_smoke_detector:demo_wwn_account:hallway_smoke:manual_test_active" } +DateTime Smoke_Last_Connection "Last Connection [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_smoke_detector:demo_wwn_account:hallway_smoke:last_connection" } +DateTime Smoke_Last_Manual_Test "Last Manual Test [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_smoke_detector:demo_wwn_account:hallway_smoke:last_manual_test_time" } +String Smoke_Smoke_Alarm "Smoke Alarm [%s]" { channel="nest:wwn_smoke_detector:demo_wwn_account:hallway_smoke:smoke_alarm_state" } +String Smoke_UI_Color "UI Color [%s]" { channel="nest:wwn_smoke_detector:demo_wwn_account:hallway_smoke:ui_color_state" } + +/* WWN Thermostat */ +Switch Thermostat_Can_Cool "Can Cool" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:can_cool" } +Switch Thermostat_Can_Heat "Can Heat" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:can_heat" } +Number:Temperature Therm_EMaxSP "Eco Max Set Point [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:eco_max_set_point" } +Number:Temperature Therm_EMinSP "Eco Min Set Point [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:eco_min_set_point" } +Switch Thermostat_FT_Active "Fan Timer Active" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:fan_timer_active" } +Number:Time Thermostat_FT_Duration "Fan Timer Duration [%d %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:fan_timer_duration" } +DateTime Thermostat_FT_Timeout "Fan Timer Timeout [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:fan_timer_timeout" } +Switch Thermostat_Has_Fan "Has Fan" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:has_fan" } +Switch Thermostat_Has_Leaf "Has Leaf" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:has_leaf" } +Number:Dimensionless Therm_Hum "Humidity [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:humidity" } +DateTime Thermostat_Last_Conn "Last Connection [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:last_connection" } +Switch Thermostat_Locked "Locked" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:locked" } +Number:Temperature Therm_LMaxSP "Locked Max Set Point [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:locked_max_set_point" } +Number:Temperature Therm_LMinSP "Locked Min Set Point [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:locked_min_set_point" } +Number:Temperature Therm_Max_SP "Max Set Point [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:max_set_point" } +Number:Temperature Therm_Min_SP "Min Set Point [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:min_set_point" } +String Thermostat_Mode "Mode [%s]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:mode" } +String Thermostat_Previous_Mode "Previous Mode [%s]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:previous_mode" } +String Thermostat_State "State [%s]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:state" } +Number:Temperature Thermostat_SP "Set Point [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:set_point" } +Switch Thermostat_Sunlight_CA "Sunlight Correction Active" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:sunlight_correction_active" } +Switch Thermostat_Sunlight_CE "Sunlight Correction Enabled" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:sunlight_correction_enabled" } +Number:Temperature Therm_Temp "Temperature [%.1f %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:temperature" } +Number:Time Therm_Time_To_Target "Time To Target [%d %unit%]" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:time_to_target" } +Switch Thermostat_Using_Em_Heat "Using Emergency Heat" { channel="nest:wwn_thermostat:demo_wwn_account:living_thermostat:using_emergency_heat" } + +/* WWN Structure */ +String Home_Away "Away [%s]" { channel="nest:wwn_structure:demo_wwn_account:home:away" } +String Home_Country_Code "Country Code [%s]" { channel="nest:wwn_structure:demo_wwn_account:home:country_code" } +String Home_CO_Alarm_State "CO Alarm State [%s]" { channel="nest:wwn_structure:demo_wwn_account:home:co_alarm_state" } +DateTime Home_ETA "ETA [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_structure:demo_wwn_account:home:eta_begin" } +DateTime Home_PP_End_Time "PP End Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_structure:demo_wwn_account:home:peak_period_end_time" } +DateTime Home_PP_Start_Time "PP Start Time [%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS]" { channel="nest:wwn_structure:demo_wwn_account:home:peak_period_start_time" } +String Home_Postal_Code "Postal Code [%s]" { channel="nest:wwn_structure:demo_wwn_account:home:postal_code" } +Switch Home_Rush_Hour_Rewards "Rush Hour Rewards" { channel="nest:wwn_structure:demo_wwn_account:home:rush_hour_rewards_enrollment" } +String Home_Security_State "Security State [%s]" { channel="nest:wwn_structure:demo_wwn_account:home:security_state" } +String Home_Smoke_Alarm_State "Smoke Alarm State [%s]" { channel="nest:wwn_structure:demo_wwn_account:home:smoke_alarm_state" } +String Home_Time_Zone "Time Zone [%s]" { channel="nest:wwn_structure:demo_wwn_account:home:time_zone" } ``` ## Attribution diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestBindingConstants.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestBindingConstants.java deleted file mode 100644 index 2c8f5dd35c..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestBindingConstants.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal; - -import java.time.Duration; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.core.thing.ThingTypeUID; - -/** - * The {@link NestBindingConstants} class defines common constants, which are - * used across the whole binding. - * - * @author David Bennett - Initial contribution - */ -@NonNullByDefault -public class NestBindingConstants { - - public static final String BINDING_ID = "nest"; - - /** The URL to use to connect to Nest with. */ - public static final String NEST_URL = "https://developer-api.nest.com"; - - /** The URL to get the access token when talking to Nest. */ - public static final String NEST_ACCESS_TOKEN_URL = "https://api.home.nest.com/oauth2/access_token"; - - /** The path to set values on the thermostat when talking to Nest. */ - public static final String NEST_THERMOSTAT_UPDATE_PATH = "/devices/thermostats/"; - - /** The path to set values on the structure when talking to Nest. */ - public static final String NEST_STRUCTURE_UPDATE_PATH = "/structures/"; - - /** The path to set values on the camera when talking to Nest. */ - public static final String NEST_CAMERA_UPDATE_PATH = "/devices/cameras/"; - - /** The path to set values on the camera when talking to Nest. */ - public static final String NEST_SMOKE_ALARM_UPDATE_PATH = "/devices/smoke_co_alarms/"; - - /** The JSON content type used when talking to Nest. */ - public static final String JSON_CONTENT_TYPE = "application/json"; - - /** To keep the streaming REST connection alive Nest sends every 30 seconds a message. */ - public static final long KEEP_ALIVE_MILLIS = Duration.ofSeconds(30).toMillis(); - - /** To avoid API throttling errors (429 Too Many Requests) Nest recommends making at most one call per minute. */ - public static final int MIN_SECONDS_BETWEEN_API_CALLS = 60; - - // List of all Thing Type UIDs - public static final ThingTypeUID THING_TYPE_THERMOSTAT = new ThingTypeUID(BINDING_ID, "thermostat"); - public static final ThingTypeUID THING_TYPE_CAMERA = new ThingTypeUID(BINDING_ID, "camera"); - public static final ThingTypeUID THING_TYPE_SMOKE_DETECTOR = new ThingTypeUID(BINDING_ID, "smoke_detector"); - public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "account"); - public static final ThingTypeUID THING_TYPE_STRUCTURE = new ThingTypeUID(BINDING_ID, "structure"); - - // List of all channel group prefixes - public static final String CHANNEL_GROUP_CAMERA_PREFIX = "camera#"; - public static final String CHANNEL_GROUP_LAST_EVENT_PREFIX = "last_event#"; - - // List of all Channel IDs - // read only channels (common) - public static final String CHANNEL_LAST_CONNECTION = "last_connection"; - - // read/write channels (thermostat) - public static final String CHANNEL_MODE = "mode"; - public static final String CHANNEL_SET_POINT = "set_point"; - public static final String CHANNEL_MAX_SET_POINT = "max_set_point"; - public static final String CHANNEL_MIN_SET_POINT = "min_set_point"; - public static final String CHANNEL_FAN_TIMER_ACTIVE = "fan_timer_active"; - public static final String CHANNEL_FAN_TIMER_DURATION = "fan_timer_duration"; - - // read only channels (thermostat) - public static final String CHANNEL_ECO_MAX_SET_POINT = "eco_max_set_point"; - public static final String CHANNEL_ECO_MIN_SET_POINT = "eco_min_set_point"; - public static final String CHANNEL_LOCKED = "locked"; - public static final String CHANNEL_LOCKED_MAX_SET_POINT = "locked_max_set_point"; - public static final String CHANNEL_LOCKED_MIN_SET_POINT = "locked_min_set_point"; - public static final String CHANNEL_TEMPERATURE = "temperature"; - public static final String CHANNEL_HUMIDITY = "humidity"; - public static final String CHANNEL_PREVIOUS_MODE = "previous_mode"; - public static final String CHANNEL_STATE = "state"; - public static final String CHANNEL_CAN_HEAT = "can_heat"; - public static final String CHANNEL_CAN_COOL = "can_cool"; - public static final String CHANNEL_FAN_TIMER_TIMEOUT = "fan_timer_timeout"; - public static final String CHANNEL_HAS_FAN = "has_fan"; - public static final String CHANNEL_HAS_LEAF = "has_leaf"; - public static final String CHANNEL_SUNLIGHT_CORRECTION_ENABLED = "sunlight_correction_enabled"; - public static final String CHANNEL_SUNLIGHT_CORRECTION_ACTIVE = "sunlight_correction_active"; - public static final String CHANNEL_TIME_TO_TARGET = "time_to_target"; - public static final String CHANNEL_USING_EMERGENCY_HEAT = "using_emergency_heat"; - - // read/write channels (camera) - public static final String CHANNEL_CAMERA_STREAMING = "camera#streaming"; - - // read only channels (camera) - public static final String CHANNEL_CAMERA_AUDIO_INPUT_ENABLED = "camera#audio_input_enabled"; - public static final String CHANNEL_CAMERA_VIDEO_HISTORY_ENABLED = "camera#video_history_enabled"; - public static final String CHANNEL_CAMERA_WEB_URL = "camera#web_url"; - public static final String CHANNEL_CAMERA_APP_URL = "camera#app_url"; - public static final String CHANNEL_CAMERA_PUBLIC_SHARE_ENABLED = "camera#public_share_enabled"; - public static final String CHANNEL_CAMERA_PUBLIC_SHARE_URL = "camera#public_share_url"; - public static final String CHANNEL_CAMERA_SNAPSHOT_URL = "camera#snapshot_url"; - public static final String CHANNEL_CAMERA_LAST_ONLINE_CHANGE = "camera#last_online_change"; - - public static final String CHANNEL_LAST_EVENT_HAS_SOUND = "last_event#has_sound"; - public static final String CHANNEL_LAST_EVENT_HAS_MOTION = "last_event#has_motion"; - public static final String CHANNEL_LAST_EVENT_HAS_PERSON = "last_event#has_person"; - public static final String CHANNEL_LAST_EVENT_START_TIME = "last_event#start_time"; - public static final String CHANNEL_LAST_EVENT_END_TIME = "last_event#end_time"; - public static final String CHANNEL_LAST_EVENT_URLS_EXPIRE_TIME = "last_event#urls_expire_time"; - public static final String CHANNEL_LAST_EVENT_WEB_URL = "last_event#web_url"; - public static final String CHANNEL_LAST_EVENT_APP_URL = "last_event#app_url"; - public static final String CHANNEL_LAST_EVENT_IMAGE_URL = "last_event#image_url"; - public static final String CHANNEL_LAST_EVENT_ANIMATED_IMAGE_URL = "last_event#animated_image_url"; - public static final String CHANNEL_LAST_EVENT_ACTIVITY_ZONES = "last_event#activity_zones"; - - // read/write channels (smoke detector) - - // read only channels (smoke detector) - public static final String CHANNEL_UI_COLOR_STATE = "ui_color_state"; - public static final String CHANNEL_LOW_BATTERY = "low_battery"; - public static final String CHANNEL_CO_ALARM_STATE = "co_alarm_state"; // Also in structure - public static final String CHANNEL_SMOKE_ALARM_STATE = "smoke_alarm_state"; // Also in structure - public static final String CHANNEL_MANUAL_TEST_ACTIVE = "manual_test_active"; - public static final String CHANNEL_LAST_MANUAL_TEST_TIME = "last_manual_test_time"; - - // read/write channel (structure) - public static final String CHANNEL_AWAY = "away"; - - // read only channels (structure) - public static final String CHANNEL_COUNTRY_CODE = "country_code"; - public static final String CHANNEL_POSTAL_CODE = "postal_code"; - public static final String CHANNEL_PEAK_PERIOD_START_TIME = "peak_period_start_time"; - public static final String CHANNEL_PEAK_PERIOD_END_TIME = "peak_period_end_time"; - public static final String CHANNEL_TIME_ZONE = "time_zone"; - public static final String CHANNEL_ETA_BEGIN = "eta_begin"; - public static final String CHANNEL_RUSH_HOUR_REWARDS_ENROLLMENT = "rush_hour_rewards_enrollment"; - public static final String CHANNEL_SECURITY_STATE = "security_state"; -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestHandlerFactory.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestHandlerFactory.java deleted file mode 100644 index d7cf754cfb..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestHandlerFactory.java +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal; - -import static java.util.stream.Collectors.toSet; -import static org.openhab.binding.nest.internal.NestBindingConstants.*; - -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; -import java.util.Set; -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.openhab.binding.nest.internal.discovery.NestDiscoveryService; -import org.openhab.binding.nest.internal.handler.NestBridgeHandler; -import org.openhab.binding.nest.internal.handler.NestCameraHandler; -import org.openhab.binding.nest.internal.handler.NestSmokeDetectorHandler; -import org.openhab.binding.nest.internal.handler.NestStructureHandler; -import org.openhab.binding.nest.internal.handler.NestThermostatHandler; -import org.openhab.core.config.discovery.DiscoveryService; -import org.openhab.core.thing.Bridge; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingTypeUID; -import org.openhab.core.thing.ThingUID; -import org.openhab.core.thing.binding.BaseThingHandlerFactory; -import org.openhab.core.thing.binding.ThingHandler; -import org.openhab.core.thing.binding.ThingHandlerFactory; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.jaxrs.client.SseEventSourceFactory; - -/** - * The {@link NestHandlerFactory} is responsible for creating things and thing - * handlers. It also sets up the discovery service to track things from the bridge - * when the bridge is created. - * - * @author David Bennett - Initial contribution - */ -@NonNullByDefault -@Component(service = ThingHandlerFactory.class, configurationPid = "binding.nest") -public class NestHandlerFactory extends BaseThingHandlerFactory { - private static final Set SUPPORTED_THING_TYPES_UIDS = Stream.of(THING_TYPE_THERMOSTAT, - THING_TYPE_CAMERA, THING_TYPE_BRIDGE, THING_TYPE_STRUCTURE, THING_TYPE_SMOKE_DETECTOR).collect(toSet()); - - private final ClientBuilder clientBuilder; - private final SseEventSourceFactory eventSourceFactory; - private final Map> discoveryService = new HashMap<>(); - - @Activate - public NestHandlerFactory(@Reference ClientBuilder clientBuilder, - @Reference SseEventSourceFactory eventSourceFactory) { - this.clientBuilder = clientBuilder; - this.eventSourceFactory = eventSourceFactory; - } - - /** - * The things this factory supports creating. - */ - @Override - public boolean supportsThingType(ThingTypeUID thingTypeUID) { - return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID); - } - - /** - * Creates a handler for the specific thing. THis also creates the discovery service - * when the bridge is created. - */ - @Override - protected @Nullable ThingHandler createHandler(Thing thing) { - ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - - if (THING_TYPE_THERMOSTAT.equals(thingTypeUID)) { - return new NestThermostatHandler(thing); - } - - if (THING_TYPE_CAMERA.equals(thingTypeUID)) { - return new NestCameraHandler(thing); - } - - if (THING_TYPE_STRUCTURE.equals(thingTypeUID)) { - return new NestStructureHandler(thing); - } - - if (THING_TYPE_SMOKE_DETECTOR.equals(thingTypeUID)) { - return new NestSmokeDetectorHandler(thing); - } - - if (THING_TYPE_BRIDGE.equals(thingTypeUID)) { - NestBridgeHandler handler = new NestBridgeHandler((Bridge) thing, clientBuilder, eventSourceFactory); - NestDiscoveryService service = new NestDiscoveryService(handler); - service.activate(); - // Register the discovery service. - discoveryService.put(handler.getThing().getUID(), - bundleContext.registerService(DiscoveryService.class.getName(), service, new Hashtable<>())); - return handler; - } - - return null; - } - - /** - * Removes the handler for the specific thing. This also handles disabling the discovery - * service when the bridge is removed. - */ - @Override - protected void removeHandler(ThingHandler thingHandler) { - if (thingHandler instanceof NestBridgeHandler) { - ServiceRegistration reg = discoveryService.get(thingHandler.getThing().getUID()); - if (reg != null) { - // Unregister the discovery service. - NestDiscoveryService service = (NestDiscoveryService) bundleContext.getService(reg.getReference()); - service.deactivate(); - reg.unregister(); - discoveryService.remove(thingHandler.getThing().getUID()); - } - } - super.removeHandler(thingHandler); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestUtils.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestUtils.java deleted file mode 100644 index 7ad59b4c54..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/NestUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal; - -import java.io.Reader; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -/** - * Utility class for sharing utility methods between objects. - * - * @author Wouter Born - Initial contribution - */ -@NonNullByDefault -public final class NestUtils { - - private static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); - - private NestUtils() { - // hidden utility class constructor - } - - public static T fromJson(String json, Class dataClass) { - return GSON.fromJson(json, dataClass); - } - - public static T fromJson(Reader reader, Class dataClass) { - return GSON.fromJson(reader, dataClass); - } - - public static String toJson(Object object) { - return GSON.toJson(object); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestBridgeConfiguration.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestBridgeConfiguration.java deleted file mode 100644 index 0de3318e0f..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestBridgeConfiguration.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - -/** - * The configuration for the Nest bridge, allowing it to talk to Nest. - * - * @author David Bennett - Initial contribution - */ -@NonNullByDefault -public class NestBridgeConfiguration { - public static final String PRODUCT_ID = "productId"; - /** Product ID from the Nest product page. */ - public String productId = ""; - - public static final String PRODUCT_SECRET = "productSecret"; - /** Product secret from the Nest product page. */ - public String productSecret = ""; - - public static final String PINCODE = "pincode"; - /** Product pincode from the Nest authorization page. */ - public @Nullable String pincode; - - public static final String ACCESS_TOKEN = "accessToken"; - /** The access token to use once retrieved from Nest. */ - public @Nullable String accessToken; -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestDeviceConfiguration.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestDeviceConfiguration.java deleted file mode 100644 index 8815397e87..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestDeviceConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * The configuration for Nest devices. - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Add device configuration to allow file based configuration - */ -@NonNullByDefault -public class NestDeviceConfiguration { - public static final String DEVICE_ID = "deviceId"; - /** Device ID which can be retrieved with the Nest API. */ - public String deviceId = ""; -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestStructureConfiguration.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestStructureConfiguration.java deleted file mode 100644 index afbf67b4df..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/config/NestStructureConfiguration.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; - -/** - * The configuration for structures. - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Add device configuration to allow file based configuration - */ -@NonNullByDefault -public class NestStructureConfiguration { - public static final String STRUCTURE_ID = "structureId"; - /** Structure ID which can be retrieved with the Nest API. */ - public String structureId = ""; -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/AccessTokenData.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/AccessTokenData.java deleted file mode 100644 index 504f9947be..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/AccessTokenData.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -/** - * Deals with the access token data that comes back from Nest when it is requested. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class AccessTokenData { - - private String accessToken; - private Long expiresIn; - - public String getAccessToken() { - return accessToken; - } - - public Long getExpiresIn() { - return expiresIn; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - AccessTokenData other = (AccessTokenData) obj; - if (accessToken == null) { - if (other.accessToken != null) { - return false; - } - } else if (!accessToken.equals(other.accessToken)) { - return false; - } - if (expiresIn == null) { - if (other.expiresIn != null) { - return false; - } - } else if (!expiresIn.equals(other.expiresIn)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((accessToken == null) ? 0 : accessToken.hashCode()); - result = prime * result + ((expiresIn == null) ? 0 : expiresIn.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("AccessTokenData [accessToken=").append(accessToken).append(", expiresIn=").append(expiresIn) - .append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ActivityZone.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ActivityZone.java deleted file mode 100644 index e548407ec5..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ActivityZone.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -/** - * The data for a camera activity zone. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Extract ActivityZone object from Camera - */ -public class ActivityZone { - - private String name; - private int id; - - public String getName() { - return name; - } - - public int getId() { - return id; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - ActivityZone other = (ActivityZone) obj; - if (id != other.id) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + id; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("CameraActivityZone [name=").append(name).append(", id=").append(id).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/BaseNestDevice.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/BaseNestDevice.java deleted file mode 100644 index 8f2d23ebab..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/BaseNestDevice.java +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Date; - -/** - * Default properties shared across all Nest devices. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class BaseNestDevice implements NestIdentifiable { - - private String deviceId; - private String name; - private String nameLong; - private Date lastConnection; - private Boolean isOnline; - private String softwareVersion; - private String structureId; - - private String whereId; - - @Override - public String getId() { - return deviceId; - } - - public String getName() { - return name; - } - - public String getDeviceId() { - return deviceId; - } - - public Date getLastConnection() { - return lastConnection; - } - - public Boolean isOnline() { - return isOnline; - } - - public String getNameLong() { - return nameLong; - } - - public String getSoftwareVersion() { - return softwareVersion; - } - - public String getStructureId() { - return structureId; - } - - public String getWhereId() { - return whereId; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - BaseNestDevice other = (BaseNestDevice) obj; - if (deviceId == null) { - if (other.deviceId != null) { - return false; - } - } else if (!deviceId.equals(other.deviceId)) { - return false; - } - if (isOnline == null) { - if (other.isOnline != null) { - return false; - } - } else if (!isOnline.equals(other.isOnline)) { - return false; - } - if (lastConnection == null) { - if (other.lastConnection != null) { - return false; - } - } else if (!lastConnection.equals(other.lastConnection)) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (nameLong == null) { - if (other.nameLong != null) { - return false; - } - } else if (!nameLong.equals(other.nameLong)) { - return false; - } - if (softwareVersion == null) { - if (other.softwareVersion != null) { - return false; - } - } else if (!softwareVersion.equals(other.softwareVersion)) { - return false; - } - if (structureId == null) { - if (other.structureId != null) { - return false; - } - } else if (!structureId.equals(other.structureId)) { - return false; - } - if (whereId == null) { - if (other.whereId != null) { - return false; - } - } else if (!whereId.equals(other.whereId)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((deviceId == null) ? 0 : deviceId.hashCode()); - result = prime * result + ((isOnline == null) ? 0 : isOnline.hashCode()); - result = prime * result + ((lastConnection == null) ? 0 : lastConnection.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((nameLong == null) ? 0 : nameLong.hashCode()); - result = prime * result + ((softwareVersion == null) ? 0 : softwareVersion.hashCode()); - result = prime * result + ((structureId == null) ? 0 : structureId.hashCode()); - result = prime * result + ((whereId == null) ? 0 : whereId.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("BaseNestDevice [deviceId=").append(deviceId).append(", name=").append(name) - .append(", nameLong=").append(nameLong).append(", lastConnection=").append(lastConnection) - .append(", isOnline=").append(isOnline).append(", softwareVersion=").append(softwareVersion) - .append(", structureId=").append(structureId).append(", whereId=").append(whereId).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Camera.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Camera.java deleted file mode 100644 index f45ffabe23..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Camera.java +++ /dev/null @@ -1,209 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Date; -import java.util.List; - -/** - * The data for the camera. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class Camera extends BaseNestDevice { - - private Boolean isStreaming; - private Boolean isAudioInputEnabled; - private Date lastIsOnlineChange; - private Boolean isVideoHistoryEnabled; - private String webUrl; - private String appUrl; - private Boolean isPublicShareEnabled; - private List activityZones; - private String publicShareUrl; - private String snapshotUrl; - private CameraEvent lastEvent; - - public Boolean isStreaming() { - return isStreaming; - } - - public Boolean isAudioInputEnabled() { - return isAudioInputEnabled; - } - - public Date getLastIsOnlineChange() { - return lastIsOnlineChange; - } - - public Boolean isVideoHistoryEnabled() { - return isVideoHistoryEnabled; - } - - public String getWebUrl() { - return webUrl; - } - - public String getAppUrl() { - return appUrl; - } - - public Boolean isPublicShareEnabled() { - return isPublicShareEnabled; - } - - public List getActivityZones() { - return activityZones; - } - - public String getPublicShareUrl() { - return publicShareUrl; - } - - public String getSnapshotUrl() { - return snapshotUrl; - } - - public CameraEvent getLastEvent() { - return lastEvent; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Camera other = (Camera) obj; - if (activityZones == null) { - if (other.activityZones != null) { - return false; - } - } else if (!activityZones.equals(other.activityZones)) { - return false; - } - if (appUrl == null) { - if (other.appUrl != null) { - return false; - } - } else if (!appUrl.equals(other.appUrl)) { - return false; - } - if (isAudioInputEnabled == null) { - if (other.isAudioInputEnabled != null) { - return false; - } - } else if (!isAudioInputEnabled.equals(other.isAudioInputEnabled)) { - return false; - } - if (isPublicShareEnabled == null) { - if (other.isPublicShareEnabled != null) { - return false; - } - } else if (!isPublicShareEnabled.equals(other.isPublicShareEnabled)) { - return false; - } - if (isStreaming == null) { - if (other.isStreaming != null) { - return false; - } - } else if (!isStreaming.equals(other.isStreaming)) { - return false; - } - if (isVideoHistoryEnabled == null) { - if (other.isVideoHistoryEnabled != null) { - return false; - } - } else if (!isVideoHistoryEnabled.equals(other.isVideoHistoryEnabled)) { - return false; - } - if (lastEvent == null) { - if (other.lastEvent != null) { - return false; - } - } else if (!lastEvent.equals(other.lastEvent)) { - return false; - } - if (lastIsOnlineChange == null) { - if (other.lastIsOnlineChange != null) { - return false; - } - } else if (!lastIsOnlineChange.equals(other.lastIsOnlineChange)) { - return false; - } - if (publicShareUrl == null) { - if (other.publicShareUrl != null) { - return false; - } - } else if (!publicShareUrl.equals(other.publicShareUrl)) { - return false; - } - if (snapshotUrl == null) { - if (other.snapshotUrl != null) { - return false; - } - } else if (!snapshotUrl.equals(other.snapshotUrl)) { - return false; - } - if (webUrl == null) { - if (other.webUrl != null) { - return false; - } - } else if (!webUrl.equals(other.webUrl)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((activityZones == null) ? 0 : activityZones.hashCode()); - result = prime * result + ((appUrl == null) ? 0 : appUrl.hashCode()); - result = prime * result + ((isAudioInputEnabled == null) ? 0 : isAudioInputEnabled.hashCode()); - result = prime * result + ((isPublicShareEnabled == null) ? 0 : isPublicShareEnabled.hashCode()); - result = prime * result + ((isStreaming == null) ? 0 : isStreaming.hashCode()); - result = prime * result + ((isVideoHistoryEnabled == null) ? 0 : isVideoHistoryEnabled.hashCode()); - result = prime * result + ((lastEvent == null) ? 0 : lastEvent.hashCode()); - result = prime * result + ((lastIsOnlineChange == null) ? 0 : lastIsOnlineChange.hashCode()); - result = prime * result + ((publicShareUrl == null) ? 0 : publicShareUrl.hashCode()); - result = prime * result + ((snapshotUrl == null) ? 0 : snapshotUrl.hashCode()); - result = prime * result + ((webUrl == null) ? 0 : webUrl.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Camera [isStreaming=").append(isStreaming).append(", isAudioInputEnabled=") - .append(isAudioInputEnabled).append(", lastIsOnlineChange=").append(lastIsOnlineChange) - .append(", isVideoHistoryEnabled=").append(isVideoHistoryEnabled).append(", webUrl=").append(webUrl) - .append(", appUrl=").append(appUrl).append(", isPublicShareEnabled=").append(isPublicShareEnabled) - .append(", activityZones=").append(activityZones).append(", publicShareUrl=").append(publicShareUrl) - .append(", snapshotUrl=").append(snapshotUrl).append(", lastEvent=").append(lastEvent) - .append(", getId()=").append(getId()).append(", getName()=").append(getName()) - .append(", getDeviceId()=").append(getDeviceId()).append(", getLastConnection()=") - .append(getLastConnection()).append(", isOnline()=").append(isOnline()).append(", getNameLong()=") - .append(getNameLong()).append(", getSoftwareVersion()=").append(getSoftwareVersion()) - .append(", getStructureId()=").append(getStructureId()).append(", getWhereId()=").append(getWhereId()) - .append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/CameraEvent.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/CameraEvent.java deleted file mode 100644 index 4545d4247b..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/CameraEvent.java +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Date; -import java.util.List; - -/** - * The data for a camera event. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Extract CameraEvent object from Camera - * @author Wouter Born - Add equals, hashCode, toString methods - */ -public class CameraEvent { - - private Boolean hasSound; - private Boolean hasMotion; - private Boolean hasPerson; - private Date startTime; - private Date endTime; - private Date urlsExpireTime; - private String webUrl; - private String appUrl; - private String imageUrl; - private String animatedImageUrl; - private List activityZoneIds; - - public Boolean isHasSound() { - return hasSound; - } - - public Boolean isHasMotion() { - return hasMotion; - } - - public Boolean isHasPerson() { - return hasPerson; - } - - public Date getStartTime() { - return startTime; - } - - public Date getEndTime() { - return endTime; - } - - public Date getUrlsExpireTime() { - return urlsExpireTime; - } - - public String getWebUrl() { - return webUrl; - } - - public String getAppUrl() { - return appUrl; - } - - public String getImageUrl() { - return imageUrl; - } - - public String getAnimatedImageUrl() { - return animatedImageUrl; - } - - public List getActivityZones() { - return activityZoneIds; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - CameraEvent other = (CameraEvent) obj; - if (activityZoneIds == null) { - if (other.activityZoneIds != null) { - return false; - } - } else if (!activityZoneIds.equals(other.activityZoneIds)) { - return false; - } - if (animatedImageUrl == null) { - if (other.animatedImageUrl != null) { - return false; - } - } else if (!animatedImageUrl.equals(other.animatedImageUrl)) { - return false; - } - if (appUrl == null) { - if (other.appUrl != null) { - return false; - } - } else if (!appUrl.equals(other.appUrl)) { - return false; - } - if (endTime == null) { - if (other.endTime != null) { - return false; - } - } else if (!endTime.equals(other.endTime)) { - return false; - } - if (hasMotion == null) { - if (other.hasMotion != null) { - return false; - } - } else if (!hasMotion.equals(other.hasMotion)) { - return false; - } - if (hasPerson == null) { - if (other.hasPerson != null) { - return false; - } - } else if (!hasPerson.equals(other.hasPerson)) { - return false; - } - if (hasSound == null) { - if (other.hasSound != null) { - return false; - } - } else if (!hasSound.equals(other.hasSound)) { - return false; - } - if (imageUrl == null) { - if (other.imageUrl != null) { - return false; - } - } else if (!imageUrl.equals(other.imageUrl)) { - return false; - } - if (startTime == null) { - if (other.startTime != null) { - return false; - } - } else if (!startTime.equals(other.startTime)) { - return false; - } - if (urlsExpireTime == null) { - if (other.urlsExpireTime != null) { - return false; - } - } else if (!urlsExpireTime.equals(other.urlsExpireTime)) { - return false; - } - if (webUrl == null) { - if (other.webUrl != null) { - return false; - } - } else if (!webUrl.equals(other.webUrl)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((activityZoneIds == null) ? 0 : activityZoneIds.hashCode()); - result = prime * result + ((animatedImageUrl == null) ? 0 : animatedImageUrl.hashCode()); - result = prime * result + ((appUrl == null) ? 0 : appUrl.hashCode()); - result = prime * result + ((endTime == null) ? 0 : endTime.hashCode()); - result = prime * result + ((hasMotion == null) ? 0 : hasMotion.hashCode()); - result = prime * result + ((hasPerson == null) ? 0 : hasPerson.hashCode()); - result = prime * result + ((hasSound == null) ? 0 : hasSound.hashCode()); - result = prime * result + ((imageUrl == null) ? 0 : imageUrl.hashCode()); - result = prime * result + ((startTime == null) ? 0 : startTime.hashCode()); - result = prime * result + ((urlsExpireTime == null) ? 0 : urlsExpireTime.hashCode()); - result = prime * result + ((webUrl == null) ? 0 : webUrl.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Event [hasSound=").append(hasSound).append(", hasMotion=").append(hasMotion) - .append(", hasPerson=").append(hasPerson).append(", startTime=").append(startTime).append(", endTime=") - .append(endTime).append(", urlsExpireTime=").append(urlsExpireTime).append(", webUrl=").append(webUrl) - .append(", appUrl=").append(appUrl).append(", imageUrl=").append(imageUrl).append(", animatedImageUrl=") - .append(animatedImageUrl).append(", activityZoneIds=").append(activityZoneIds).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ETA.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ETA.java deleted file mode 100644 index e398563118..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ETA.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Date; - -/** - * Used to set and update the ETA values for Nest. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Extract ETA object from Structure - * @author Wouter Born - Add equals, hashCode, toString methods - */ -public class ETA { - - private String tripId; - private Date estimatedArrivalWindowBegin; - private Date estimatedArrivalWindowEnd; - - public String getTripId() { - return tripId; - } - - public void setTripId(String tripId) { - this.tripId = tripId; - } - - public Date getEstimatedArrivalWindowBegin() { - return estimatedArrivalWindowBegin; - } - - public void setEstimatedArrivalWindowBegin(Date estimatedArrivalWindowBegin) { - this.estimatedArrivalWindowBegin = estimatedArrivalWindowBegin; - } - - public Date getEstimatedArrivalWindowEnd() { - return estimatedArrivalWindowEnd; - } - - public void setEstimatedArrivalWindowEnd(Date estimatedArrivalWindowEnd) { - this.estimatedArrivalWindowEnd = estimatedArrivalWindowEnd; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - ETA other = (ETA) obj; - if (estimatedArrivalWindowBegin == null) { - if (other.estimatedArrivalWindowBegin != null) { - return false; - } - } else if (!estimatedArrivalWindowBegin.equals(other.estimatedArrivalWindowBegin)) { - return false; - } - if (estimatedArrivalWindowEnd == null) { - if (other.estimatedArrivalWindowEnd != null) { - return false; - } - } else if (!estimatedArrivalWindowEnd.equals(other.estimatedArrivalWindowEnd)) { - return false; - } - if (tripId == null) { - if (other.tripId != null) { - return false; - } - } else if (!tripId.equals(other.tripId)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((estimatedArrivalWindowBegin == null) ? 0 : estimatedArrivalWindowBegin.hashCode()); - result = prime * result + ((estimatedArrivalWindowEnd == null) ? 0 : estimatedArrivalWindowEnd.hashCode()); - result = prime * result + ((tripId == null) ? 0 : tripId.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("ETA [tripId=").append(tripId).append(", estimatedArrivalWindowBegin=") - .append(estimatedArrivalWindowBegin).append(", estimatedArrivalWindowEnd=") - .append(estimatedArrivalWindowEnd).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ErrorData.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ErrorData.java deleted file mode 100644 index 5f6acd7780..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/ErrorData.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -/** - * The data of Nest API errors. - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Improve exception handling - * @author Wouter Born - Add equals and hashCode methods - */ -public class ErrorData { - - private String error; - private String type; - private String message; - private String instance; - - public String getError() { - return error; - } - - public String getType() { - return type; - } - - public String getMessage() { - return message; - } - - public String getInstance() { - return instance; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - ErrorData other = (ErrorData) obj; - if (error == null) { - if (other.error != null) { - return false; - } - } else if (!error.equals(other.error)) { - return false; - } - if (instance == null) { - if (other.instance != null) { - return false; - } - } else if (!instance.equals(other.instance)) { - return false; - } - if (message == null) { - if (other.message != null) { - return false; - } - } else if (!message.equals(other.message)) { - return false; - } - if (type == null) { - if (other.type != null) { - return false; - } - } else if (!type.equals(other.type)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((error == null) ? 0 : error.hashCode()); - result = prime * result + ((instance == null) ? 0 : instance.hashCode()); - result = prime * result + ((message == null) ? 0 : message.hashCode()); - result = prime * result + ((type == null) ? 0 : type.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("ErrorData [error=").append(error).append(", type=").append(type).append(", message=") - .append(message).append(", instance=").append(instance).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestDevices.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestDevices.java deleted file mode 100644 index f17ae0ae96..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestDevices.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Map; - -/** - * All the Nest devices broken up by type. - * - * @author David Bennett - Initial contribution - */ -public class NestDevices { - - private Map thermostats; - private Map smokeCoAlarms; - private Map cameras; - - /** Id to thermostat mapping */ - public Map getThermostats() { - return thermostats; - } - - /** Id to camera mapping */ - public Map getCameras() { - return cameras; - } - - /** Id to smoke detector */ - public Map getSmokeCoAlarms() { - return smokeCoAlarms; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - NestDevices other = (NestDevices) obj; - if (cameras == null) { - if (other.cameras != null) { - return false; - } - } else if (!cameras.equals(other.cameras)) { - return false; - } - if (smokeCoAlarms == null) { - if (other.smokeCoAlarms != null) { - return false; - } - } else if (!smokeCoAlarms.equals(other.smokeCoAlarms)) { - return false; - } - if (thermostats == null) { - if (other.thermostats != null) { - return false; - } - } else if (!thermostats.equals(other.thermostats)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((cameras == null) ? 0 : cameras.hashCode()); - result = prime * result + ((smokeCoAlarms == null) ? 0 : smokeCoAlarms.hashCode()); - result = prime * result + ((thermostats == null) ? 0 : thermostats.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("NestDevices [thermostats=").append(thermostats).append(", smokeCoAlarms=").append(smokeCoAlarms) - .append(", cameras=").append(cameras).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestIdentifiable.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestIdentifiable.java deleted file mode 100644 index 09952e1837..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestIdentifiable.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -/** - * Interface for uniquely identifiable Nest objects (device or a structure). - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Simplify working with deviceId and structureId - */ -public interface NestIdentifiable { - - /** - * Returns the identifier that uniquely identifies the Nest object (deviceId or structureId). - */ - String getId(); -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestMetadata.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestMetadata.java deleted file mode 100644 index 3c4530fc1b..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/NestMetadata.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -/** - * The meta data in the data downloads from Nest. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class NestMetadata { - - private String accessToken; - private String clientVersion; - - public String getAccessToken() { - return accessToken; - } - - public String getClientVersion() { - return clientVersion; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - NestMetadata other = (NestMetadata) obj; - if (accessToken == null) { - if (other.accessToken != null) { - return false; - } - } else if (!accessToken.equals(other.accessToken)) { - return false; - } - if (clientVersion == null) { - if (other.clientVersion != null) { - return false; - } - } else if (!clientVersion.equals(other.clientVersion)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((accessToken == null) ? 0 : accessToken.hashCode()); - result = prime * result + ((clientVersion == null) ? 0 : clientVersion.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("NestMetadata [accessToken=").append(accessToken).append(", clientVersion=") - .append(clientVersion).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/SmokeDetector.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/SmokeDetector.java deleted file mode 100644 index 8c791ef9ce..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/SmokeDetector.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Date; - -import com.google.gson.annotations.SerializedName; - -/** - * Data for the Nest smoke detector. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class SmokeDetector extends BaseNestDevice { - - private BatteryHealth batteryHealth; - private AlarmState coAlarmState; - private Date lastManualTestTime; - private AlarmState smokeAlarmState; - private Boolean isManualTestActive; - private UiColorState uiColorState; - - public UiColorState getUiColorState() { - return uiColorState; - } - - public BatteryHealth getBatteryHealth() { - return batteryHealth; - } - - public AlarmState getCoAlarmState() { - return coAlarmState; - } - - public Date getLastManualTestTime() { - return lastManualTestTime; - } - - public AlarmState getSmokeAlarmState() { - return smokeAlarmState; - } - - public Boolean isManualTestActive() { - return isManualTestActive; - } - - public enum BatteryHealth { - @SerializedName("ok") - OK, - @SerializedName("replace") - REPLACE - } - - public enum AlarmState { - @SerializedName("ok") - OK, - @SerializedName("emergency") - EMERGENCY, - @SerializedName("warning") - WARNING - } - - public enum UiColorState { - @SerializedName("gray") - GRAY, - @SerializedName("green") - GREEN, - @SerializedName("yellow") - YELLOW, - @SerializedName("red") - RED - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - SmokeDetector other = (SmokeDetector) obj; - if (batteryHealth != other.batteryHealth) { - return false; - } - if (coAlarmState != other.coAlarmState) { - return false; - } - if (isManualTestActive == null) { - if (other.isManualTestActive != null) { - return false; - } - } else if (!isManualTestActive.equals(other.isManualTestActive)) { - return false; - } - if (lastManualTestTime == null) { - if (other.lastManualTestTime != null) { - return false; - } - } else if (!lastManualTestTime.equals(other.lastManualTestTime)) { - return false; - } - if (smokeAlarmState != other.smokeAlarmState) { - return false; - } - if (uiColorState != other.uiColorState) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((batteryHealth == null) ? 0 : batteryHealth.hashCode()); - result = prime * result + ((coAlarmState == null) ? 0 : coAlarmState.hashCode()); - result = prime * result + ((isManualTestActive == null) ? 0 : isManualTestActive.hashCode()); - result = prime * result + ((lastManualTestTime == null) ? 0 : lastManualTestTime.hashCode()); - result = prime * result + ((smokeAlarmState == null) ? 0 : smokeAlarmState.hashCode()); - result = prime * result + ((uiColorState == null) ? 0 : uiColorState.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("SmokeDetector [batteryHealth=").append(batteryHealth).append(", coAlarmState=") - .append(coAlarmState).append(", lastManualTestTime=").append(lastManualTestTime) - .append(", smokeAlarmState=").append(smokeAlarmState).append(", isManualTestActive=") - .append(isManualTestActive).append(", uiColorState=").append(uiColorState).append(", getId()=") - .append(getId()).append(", getName()=").append(getName()).append(", getDeviceId()=") - .append(getDeviceId()).append(", getLastConnection()=").append(getLastConnection()) - .append(", isOnline()=").append(isOnline()).append(", getNameLong()=").append(getNameLong()) - .append(", getSoftwareVersion()=").append(getSoftwareVersion()).append(", getStructureId()=") - .append(getStructureId()).append(", getWhereId()=").append(getWhereId()).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Structure.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Structure.java deleted file mode 100644 index 3d3eba7390..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Structure.java +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import org.openhab.binding.nest.internal.data.SmokeDetector.AlarmState; - -import com.google.gson.annotations.SerializedName; - -/** - * The structure details from Nest. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class Structure implements NestIdentifiable { - - private String structureId; - private List thermostats; - private List smokeCoAlarms; - private List cameras; - private String countryCode; - private String postalCode; - private Date peakPeriodStartTime; - private Date peakPeriodEndTime; - private String timeZone; - private Date etaBegin; - private SmokeDetector.AlarmState coAlarmState; - private SmokeDetector.AlarmState smokeAlarmState; - private Boolean rhrEnrollment; - private Map wheres; - private HomeAwayState away; - private String name; - private ETA eta; - private SecurityState wwnSecurityState; - - @Override - public String getId() { - return structureId; - } - - public HomeAwayState getAway() { - return away; - } - - public void setAway(HomeAwayState away) { - this.away = away; - } - - public String getStructureId() { - return structureId; - } - - public List getThermostats() { - return thermostats; - } - - public List getSmokeCoAlarms() { - return smokeCoAlarms; - } - - public List getCameras() { - return cameras; - } - - public String getCountryCode() { - return countryCode; - } - - public String getPostalCode() { - return postalCode; - } - - public Date getPeakPeriodStartTime() { - return peakPeriodStartTime; - } - - public Date getPeakPeriodEndTime() { - return peakPeriodEndTime; - } - - public String getTimeZone() { - return timeZone; - } - - public Date getEtaBegin() { - return etaBegin; - } - - public AlarmState getCoAlarmState() { - return coAlarmState; - } - - public AlarmState getSmokeAlarmState() { - return smokeAlarmState; - } - - public Boolean isRhrEnrollment() { - return rhrEnrollment; - } - - public Map getWheres() { - return wheres; - } - - public ETA getEta() { - return eta; - } - - public String getName() { - return name; - } - - public SecurityState getWwnSecurityState() { - return wwnSecurityState; - } - - public enum HomeAwayState { - @SerializedName("home") - HOME, - @SerializedName("away") - AWAY, - @SerializedName("unknown") - UNKNOWN - } - - public enum SecurityState { - @SerializedName("ok") - OK, - @SerializedName("deter") - DETER - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Structure other = (Structure) obj; - if (away != other.away) { - return false; - } - if (cameras == null) { - if (other.cameras != null) { - return false; - } - } else if (!cameras.equals(other.cameras)) { - return false; - } - if (coAlarmState != other.coAlarmState) { - return false; - } - if (countryCode == null) { - if (other.countryCode != null) { - return false; - } - } else if (!countryCode.equals(other.countryCode)) { - return false; - } - if (eta == null) { - if (other.eta != null) { - return false; - } - } else if (!eta.equals(other.eta)) { - return false; - } - if (etaBegin == null) { - if (other.etaBegin != null) { - return false; - } - } else if (!etaBegin.equals(other.etaBegin)) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (peakPeriodEndTime == null) { - if (other.peakPeriodEndTime != null) { - return false; - } - } else if (!peakPeriodEndTime.equals(other.peakPeriodEndTime)) { - return false; - } - if (peakPeriodStartTime == null) { - if (other.peakPeriodStartTime != null) { - return false; - } - } else if (!peakPeriodStartTime.equals(other.peakPeriodStartTime)) { - return false; - } - if (postalCode == null) { - if (other.postalCode != null) { - return false; - } - } else if (!postalCode.equals(other.postalCode)) { - return false; - } - if (rhrEnrollment == null) { - if (other.rhrEnrollment != null) { - return false; - } - } else if (!rhrEnrollment.equals(other.rhrEnrollment)) { - return false; - } - if (smokeAlarmState != other.smokeAlarmState) { - return false; - } - if (smokeCoAlarms == null) { - if (other.smokeCoAlarms != null) { - return false; - } - } else if (!smokeCoAlarms.equals(other.smokeCoAlarms)) { - return false; - } - if (structureId == null) { - if (other.structureId != null) { - return false; - } - } else if (!structureId.equals(other.structureId)) { - return false; - } - if (thermostats == null) { - if (other.thermostats != null) { - return false; - } - } else if (!thermostats.equals(other.thermostats)) { - return false; - } - if (timeZone == null) { - if (other.timeZone != null) { - return false; - } - } else if (!timeZone.equals(other.timeZone)) { - return false; - } - if (wheres == null) { - if (other.wheres != null) { - return false; - } - } else if (!wheres.equals(other.wheres)) { - return false; - } - if (wwnSecurityState != other.wwnSecurityState) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((away == null) ? 0 : away.hashCode()); - result = prime * result + ((cameras == null) ? 0 : cameras.hashCode()); - result = prime * result + ((coAlarmState == null) ? 0 : coAlarmState.hashCode()); - result = prime * result + ((countryCode == null) ? 0 : countryCode.hashCode()); - result = prime * result + ((eta == null) ? 0 : eta.hashCode()); - result = prime * result + ((etaBegin == null) ? 0 : etaBegin.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((peakPeriodEndTime == null) ? 0 : peakPeriodEndTime.hashCode()); - result = prime * result + ((peakPeriodStartTime == null) ? 0 : peakPeriodStartTime.hashCode()); - result = prime * result + ((postalCode == null) ? 0 : postalCode.hashCode()); - result = prime * result + ((rhrEnrollment == null) ? 0 : rhrEnrollment.hashCode()); - result = prime * result + ((smokeAlarmState == null) ? 0 : smokeAlarmState.hashCode()); - result = prime * result + ((smokeCoAlarms == null) ? 0 : smokeCoAlarms.hashCode()); - result = prime * result + ((structureId == null) ? 0 : structureId.hashCode()); - result = prime * result + ((thermostats == null) ? 0 : thermostats.hashCode()); - result = prime * result + ((timeZone == null) ? 0 : timeZone.hashCode()); - result = prime * result + ((wheres == null) ? 0 : wheres.hashCode()); - result = prime * result + ((wwnSecurityState == null) ? 0 : wwnSecurityState.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Structure [structureId=").append(structureId).append(", thermostats=").append(thermostats) - .append(", smokeCoAlarms=").append(smokeCoAlarms).append(", cameras=").append(cameras) - .append(", countryCode=").append(countryCode).append(", postalCode=").append(postalCode) - .append(", peakPeriodStartTime=").append(peakPeriodStartTime).append(", peakPeriodEndTime=") - .append(peakPeriodEndTime).append(", timeZone=").append(timeZone).append(", etaBegin=").append(etaBegin) - .append(", coAlarmState=").append(coAlarmState).append(", smokeAlarmState=").append(smokeAlarmState) - .append(", rhrEnrollment=").append(rhrEnrollment).append(", wheres=").append(wheres).append(", away=") - .append(away).append(", name=").append(name).append(", eta=").append(eta).append(", wwnSecurityState=") - .append(wwnSecurityState).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Thermostat.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Thermostat.java deleted file mode 100644 index ed2c76a145..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Thermostat.java +++ /dev/null @@ -1,572 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import static org.openhab.core.library.unit.ImperialUnits.FAHRENHEIT; -import static org.openhab.core.library.unit.SIUnits.CELSIUS; - -import java.util.Date; - -import javax.measure.Unit; -import javax.measure.quantity.Temperature; - -import com.google.gson.annotations.SerializedName; - -/** - * Gson class to encapsulate the data for the Nest thermostat. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class Thermostat extends BaseNestDevice { - - private Boolean canCool; - private Boolean canHeat; - private Boolean isUsingEmergencyHeat; - private Boolean hasFan; - private Boolean fanTimerActive; - private Date fanTimerTimeout; - private Boolean hasLeaf; - private String temperatureScale; - private Double ambientTemperatureC; - private Double ambientTemperatureF; - private Integer humidity; - private Double targetTemperatureC; - private Double targetTemperatureF; - private Double targetTemperatureHighC; - private Double targetTemperatureHighF; - private Double targetTemperatureLowC; - private Double targetTemperatureLowF; - private Mode hvacMode; - private Mode previousHvacMode; - private State hvacState; - private Double ecoTemperatureHighC; - private Double ecoTemperatureHighF; - private Double ecoTemperatureLowC; - private Double ecoTemperatureLowF; - private Boolean isLocked; - private Double lockedTempMaxC; - private Double lockedTempMaxF; - private Double lockedTempMinC; - private Double lockedTempMinF; - private Boolean sunlightCorrectionEnabled; - private Boolean sunlightCorrectionActive; - private Integer fanTimerDuration; - private String timeToTarget; - private String whereName; - - public Unit getTemperatureUnit() { - if ("C".equals(temperatureScale)) { - return CELSIUS; - } else if ("F".equals(temperatureScale)) { - return FAHRENHEIT; - } else { - return null; - } - } - - public Double getTargetTemperature() { - if (getTemperatureUnit() == CELSIUS) { - return targetTemperatureC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return targetTemperatureF; - } else { - return null; - } - } - - public Double getTargetTemperatureHigh() { - if (getTemperatureUnit() == CELSIUS) { - return targetTemperatureHighC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return targetTemperatureHighF; - } else { - return null; - } - } - - public Double getTargetTemperatureLow() { - if (getTemperatureUnit() == CELSIUS) { - return targetTemperatureLowC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return targetTemperatureLowF; - } else { - return null; - } - } - - public Mode getMode() { - return hvacMode; - } - - public Double getEcoTemperatureHigh() { - if (getTemperatureUnit() == CELSIUS) { - return ecoTemperatureHighC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return ecoTemperatureHighF; - } else { - return null; - } - } - - public Double getEcoTemperatureLow() { - if (getTemperatureUnit() == CELSIUS) { - return ecoTemperatureLowC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return ecoTemperatureLowF; - } else { - return null; - } - } - - public Boolean isLocked() { - return isLocked; - } - - public Double getLockedTempMax() { - if (getTemperatureUnit() == CELSIUS) { - return lockedTempMaxC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return lockedTempMaxF; - } else { - return null; - } - } - - public Double getLockedTempMin() { - if (getTemperatureUnit() == CELSIUS) { - return lockedTempMinC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return lockedTempMinF; - } else { - return null; - } - } - - public Boolean isCanCool() { - return canCool; - } - - public Boolean isCanHeat() { - return canHeat; - } - - public Boolean isUsingEmergencyHeat() { - return isUsingEmergencyHeat; - } - - public Boolean isHasFan() { - return hasFan; - } - - public Boolean isFanTimerActive() { - return fanTimerActive; - } - - public Date getFanTimerTimeout() { - return fanTimerTimeout; - } - - public Boolean isHasLeaf() { - return hasLeaf; - } - - public Mode getPreviousHvacMode() { - return previousHvacMode; - } - - public State getHvacState() { - return hvacState; - } - - public Boolean isSunlightCorrectionEnabled() { - return sunlightCorrectionEnabled; - } - - public Boolean isSunlightCorrectionActive() { - return sunlightCorrectionActive; - } - - public Integer getFanTimerDuration() { - return fanTimerDuration; - } - - public Integer getTimeToTarget() { - return parseTimeToTarget(timeToTarget); - } - - /* - * Turns the time to target string into a real value. - */ - static Integer parseTimeToTarget(String timeToTarget) { - if (timeToTarget == null) { - return null; - } else if (timeToTarget.startsWith("~") || timeToTarget.startsWith("<") || timeToTarget.startsWith(">")) { - return Integer.valueOf(timeToTarget.substring(1)); - } - return Integer.valueOf(timeToTarget); - } - - public String getWhereName() { - return whereName; - } - - public Double getAmbientTemperature() { - if (getTemperatureUnit() == CELSIUS) { - return ambientTemperatureC; - } else if (getTemperatureUnit() == FAHRENHEIT) { - return ambientTemperatureF; - } else { - return null; - } - } - - public Integer getHumidity() { - return humidity; - } - - public enum Mode { - @SerializedName("heat") - HEAT, - @SerializedName("cool") - COOL, - @SerializedName("heat-cool") - HEAT_COOL, - @SerializedName("eco") - ECO, - @SerializedName("off") - OFF - } - - public enum State { - @SerializedName("heating") - HEATING, - @SerializedName("cooling") - COOLING, - @SerializedName("off") - OFF - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Thermostat other = (Thermostat) obj; - if (ambientTemperatureC == null) { - if (other.ambientTemperatureC != null) { - return false; - } - } else if (!ambientTemperatureC.equals(other.ambientTemperatureC)) { - return false; - } - if (ambientTemperatureF == null) { - if (other.ambientTemperatureF != null) { - return false; - } - } else if (!ambientTemperatureF.equals(other.ambientTemperatureF)) { - return false; - } - if (canCool == null) { - if (other.canCool != null) { - return false; - } - } else if (!canCool.equals(other.canCool)) { - return false; - } - if (canHeat == null) { - if (other.canHeat != null) { - return false; - } - } else if (!canHeat.equals(other.canHeat)) { - return false; - } - if (ecoTemperatureHighC == null) { - if (other.ecoTemperatureHighC != null) { - return false; - } - } else if (!ecoTemperatureHighC.equals(other.ecoTemperatureHighC)) { - return false; - } - if (ecoTemperatureHighF == null) { - if (other.ecoTemperatureHighF != null) { - return false; - } - } else if (!ecoTemperatureHighF.equals(other.ecoTemperatureHighF)) { - return false; - } - if (ecoTemperatureLowC == null) { - if (other.ecoTemperatureLowC != null) { - return false; - } - } else if (!ecoTemperatureLowC.equals(other.ecoTemperatureLowC)) { - return false; - } - if (ecoTemperatureLowF == null) { - if (other.ecoTemperatureLowF != null) { - return false; - } - } else if (!ecoTemperatureLowF.equals(other.ecoTemperatureLowF)) { - return false; - } - if (fanTimerActive == null) { - if (other.fanTimerActive != null) { - return false; - } - } else if (!fanTimerActive.equals(other.fanTimerActive)) { - return false; - } - if (fanTimerDuration == null) { - if (other.fanTimerDuration != null) { - return false; - } - } else if (!fanTimerDuration.equals(other.fanTimerDuration)) { - return false; - } - if (fanTimerTimeout == null) { - if (other.fanTimerTimeout != null) { - return false; - } - } else if (!fanTimerTimeout.equals(other.fanTimerTimeout)) { - return false; - } - if (hasFan == null) { - if (other.hasFan != null) { - return false; - } - } else if (!hasFan.equals(other.hasFan)) { - return false; - } - if (hasLeaf == null) { - if (other.hasLeaf != null) { - return false; - } - } else if (!hasLeaf.equals(other.hasLeaf)) { - return false; - } - if (humidity == null) { - if (other.humidity != null) { - return false; - } - } else if (!humidity.equals(other.humidity)) { - return false; - } - if (hvacMode != other.hvacMode) { - return false; - } - if (hvacState != other.hvacState) { - return false; - } - if (isLocked == null) { - if (other.isLocked != null) { - return false; - } - } else if (!isLocked.equals(other.isLocked)) { - return false; - } - if (isUsingEmergencyHeat == null) { - if (other.isUsingEmergencyHeat != null) { - return false; - } - } else if (!isUsingEmergencyHeat.equals(other.isUsingEmergencyHeat)) { - return false; - } - if (lockedTempMaxC == null) { - if (other.lockedTempMaxC != null) { - return false; - } - } else if (!lockedTempMaxC.equals(other.lockedTempMaxC)) { - return false; - } - if (lockedTempMaxF == null) { - if (other.lockedTempMaxF != null) { - return false; - } - } else if (!lockedTempMaxF.equals(other.lockedTempMaxF)) { - return false; - } - if (lockedTempMinC == null) { - if (other.lockedTempMinC != null) { - return false; - } - } else if (!lockedTempMinC.equals(other.lockedTempMinC)) { - return false; - } - if (lockedTempMinF == null) { - if (other.lockedTempMinF != null) { - return false; - } - } else if (!lockedTempMinF.equals(other.lockedTempMinF)) { - return false; - } - if (previousHvacMode != other.previousHvacMode) { - return false; - } - if (sunlightCorrectionActive == null) { - if (other.sunlightCorrectionActive != null) { - return false; - } - } else if (!sunlightCorrectionActive.equals(other.sunlightCorrectionActive)) { - return false; - } - if (sunlightCorrectionEnabled == null) { - if (other.sunlightCorrectionEnabled != null) { - return false; - } - } else if (!sunlightCorrectionEnabled.equals(other.sunlightCorrectionEnabled)) { - return false; - } - if (targetTemperatureC == null) { - if (other.targetTemperatureC != null) { - return false; - } - } else if (!targetTemperatureC.equals(other.targetTemperatureC)) { - return false; - } - if (targetTemperatureF == null) { - if (other.targetTemperatureF != null) { - return false; - } - } else if (!targetTemperatureF.equals(other.targetTemperatureF)) { - return false; - } - if (targetTemperatureHighC == null) { - if (other.targetTemperatureHighC != null) { - return false; - } - } else if (!targetTemperatureHighC.equals(other.targetTemperatureHighC)) { - return false; - } - if (targetTemperatureHighF == null) { - if (other.targetTemperatureHighF != null) { - return false; - } - } else if (!targetTemperatureHighF.equals(other.targetTemperatureHighF)) { - return false; - } - if (targetTemperatureLowC == null) { - if (other.targetTemperatureLowC != null) { - return false; - } - } else if (!targetTemperatureLowC.equals(other.targetTemperatureLowC)) { - return false; - } - if (targetTemperatureLowF == null) { - if (other.targetTemperatureLowF != null) { - return false; - } - } else if (!targetTemperatureLowF.equals(other.targetTemperatureLowF)) { - return false; - } - if (temperatureScale == null) { - if (other.temperatureScale != null) { - return false; - } - } else if (!temperatureScale.equals(other.temperatureScale)) { - return false; - } - if (timeToTarget == null) { - if (other.timeToTarget != null) { - return false; - } - } else if (!timeToTarget.equals(other.timeToTarget)) { - return false; - } - if (whereName == null) { - if (other.whereName != null) { - return false; - } - } else if (!whereName.equals(other.whereName)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((ambientTemperatureC == null) ? 0 : ambientTemperatureC.hashCode()); - result = prime * result + ((ambientTemperatureF == null) ? 0 : ambientTemperatureF.hashCode()); - result = prime * result + ((canCool == null) ? 0 : canCool.hashCode()); - result = prime * result + ((canHeat == null) ? 0 : canHeat.hashCode()); - result = prime * result + ((ecoTemperatureHighC == null) ? 0 : ecoTemperatureHighC.hashCode()); - result = prime * result + ((ecoTemperatureHighF == null) ? 0 : ecoTemperatureHighF.hashCode()); - result = prime * result + ((ecoTemperatureLowC == null) ? 0 : ecoTemperatureLowC.hashCode()); - result = prime * result + ((ecoTemperatureLowF == null) ? 0 : ecoTemperatureLowF.hashCode()); - result = prime * result + ((fanTimerActive == null) ? 0 : fanTimerActive.hashCode()); - result = prime * result + ((fanTimerDuration == null) ? 0 : fanTimerDuration.hashCode()); - result = prime * result + ((fanTimerTimeout == null) ? 0 : fanTimerTimeout.hashCode()); - result = prime * result + ((hasFan == null) ? 0 : hasFan.hashCode()); - result = prime * result + ((hasLeaf == null) ? 0 : hasLeaf.hashCode()); - result = prime * result + ((humidity == null) ? 0 : humidity.hashCode()); - result = prime * result + ((hvacMode == null) ? 0 : hvacMode.hashCode()); - result = prime * result + ((hvacState == null) ? 0 : hvacState.hashCode()); - result = prime * result + ((isLocked == null) ? 0 : isLocked.hashCode()); - result = prime * result + ((isUsingEmergencyHeat == null) ? 0 : isUsingEmergencyHeat.hashCode()); - result = prime * result + ((lockedTempMaxC == null) ? 0 : lockedTempMaxC.hashCode()); - result = prime * result + ((lockedTempMaxF == null) ? 0 : lockedTempMaxF.hashCode()); - result = prime * result + ((lockedTempMinC == null) ? 0 : lockedTempMinC.hashCode()); - result = prime * result + ((lockedTempMinF == null) ? 0 : lockedTempMinF.hashCode()); - result = prime * result + ((previousHvacMode == null) ? 0 : previousHvacMode.hashCode()); - result = prime * result + ((sunlightCorrectionActive == null) ? 0 : sunlightCorrectionActive.hashCode()); - result = prime * result + ((sunlightCorrectionEnabled == null) ? 0 : sunlightCorrectionEnabled.hashCode()); - result = prime * result + ((targetTemperatureC == null) ? 0 : targetTemperatureC.hashCode()); - result = prime * result + ((targetTemperatureF == null) ? 0 : targetTemperatureF.hashCode()); - result = prime * result + ((targetTemperatureHighC == null) ? 0 : targetTemperatureHighC.hashCode()); - result = prime * result + ((targetTemperatureHighF == null) ? 0 : targetTemperatureHighF.hashCode()); - result = prime * result + ((targetTemperatureLowC == null) ? 0 : targetTemperatureLowC.hashCode()); - result = prime * result + ((targetTemperatureLowF == null) ? 0 : targetTemperatureLowF.hashCode()); - result = prime * result + ((temperatureScale == null) ? 0 : temperatureScale.hashCode()); - result = prime * result + ((timeToTarget == null) ? 0 : timeToTarget.hashCode()); - result = prime * result + ((whereName == null) ? 0 : whereName.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Thermostat [canCool=").append(canCool).append(", canHeat=").append(canHeat) - .append(", isUsingEmergencyHeat=").append(isUsingEmergencyHeat).append(", hasFan=").append(hasFan) - .append(", fanTimerActive=").append(fanTimerActive).append(", fanTimerTimeout=").append(fanTimerTimeout) - .append(", hasLeaf=").append(hasLeaf).append(", temperatureScale=").append(temperatureScale) - .append(", ambientTemperatureC=").append(ambientTemperatureC).append(", ambientTemperatureF=") - .append(ambientTemperatureF).append(", humidity=").append(humidity).append(", targetTemperatureC=") - .append(targetTemperatureC).append(", targetTemperatureF=").append(targetTemperatureF) - .append(", targetTemperatureHighC=").append(targetTemperatureHighC).append(", targetTemperatureHighF=") - .append(targetTemperatureHighF).append(", targetTemperatureLowC=").append(targetTemperatureLowC) - .append(", targetTemperatureLowF=").append(targetTemperatureLowF).append(", hvacMode=").append(hvacMode) - .append(", previousHvacMode=").append(previousHvacMode).append(", hvacState=").append(hvacState) - .append(", ecoTemperatureHighC=").append(ecoTemperatureHighC).append(", ecoTemperatureHighF=") - .append(ecoTemperatureHighF).append(", ecoTemperatureLowC=").append(ecoTemperatureLowC) - .append(", ecoTemperatureLowF=").append(ecoTemperatureLowF).append(", isLocked=").append(isLocked) - .append(", lockedTempMaxC=").append(lockedTempMaxC).append(", lockedTempMaxF=").append(lockedTempMaxF) - .append(", lockedTempMinC=").append(lockedTempMinC).append(", lockedTempMinF=").append(lockedTempMinF) - .append(", sunlightCorrectionEnabled=").append(sunlightCorrectionEnabled) - .append(", sunlightCorrectionActive=").append(sunlightCorrectionActive).append(", fanTimerDuration=") - .append(fanTimerDuration).append(", timeToTarget=").append(timeToTarget).append(", whereName=") - .append(whereName).append(", getId()=").append(getId()).append(", getName()=").append(getName()) - .append(", getDeviceId()=").append(getDeviceId()).append(", getLastConnection()=") - .append(getLastConnection()).append(", isOnline()=").append(isOnline()).append(", getNameLong()=") - .append(getNameLong()).append(", getSoftwareVersion()=").append(getSoftwareVersion()) - .append(", getStructureId()=").append(getStructureId()).append(", getWhereId()=").append(getWhereId()) - .append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/TopLevelData.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/TopLevelData.java deleted file mode 100644 index 5a2e425509..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/TopLevelData.java +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -import java.util.Map; - -/** - * Top level data for all the Nest stuff, this is the format the Nest data comes back from Nest in. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add equals and hashCode methods - */ -public class TopLevelData { - - private NestDevices devices; - private NestMetadata metadata; - private Map structures; - - public NestDevices getDevices() { - return devices; - } - - public NestMetadata getMetadata() { - return metadata; - } - - public Map getStructures() { - return structures; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - TopLevelData other = (TopLevelData) obj; - if (devices == null) { - if (other.devices != null) { - return false; - } - } else if (!devices.equals(other.devices)) { - return false; - } - if (metadata == null) { - if (other.metadata != null) { - return false; - } - } else if (!metadata.equals(other.metadata)) { - return false; - } - if (structures == null) { - if (other.structures != null) { - return false; - } - } else if (!structures.equals(other.structures)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((devices == null) ? 0 : devices.hashCode()); - result = prime * result + ((metadata == null) ? 0 : metadata.hashCode()); - result = prime * result + ((structures == null) ? 0 : structures.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("TopLevelData [devices=").append(devices).append(", metadata=").append(metadata) - .append(", structures=").append(structures).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/TopLevelStreamingData.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/TopLevelStreamingData.java deleted file mode 100644 index f5bc4e11fa..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/TopLevelStreamingData.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -/** - * The top level data that is sent by Nest to a streaming REST client using SSE. - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Replace polling with REST streaming - * @author Wouter Born - Add equals and hashCode methods - */ -public class TopLevelStreamingData { - - private String path; - private TopLevelData data; - - public String getPath() { - return path; - } - - public TopLevelData getData() { - return data; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((data == null) ? 0 : data.hashCode()); - result = prime * result + ((path == null) ? 0 : path.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - TopLevelStreamingData other = (TopLevelStreamingData) obj; - if (data == null) { - if (other.data != null) { - return false; - } - } else if (!data.equals(other.data)) { - return false; - } - if (path == null) { - if (other.path != null) { - return false; - } - } else if (!path.equals(other.path)) { - return false; - } - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("TopLevelStreamingData [path=").append(path).append(", data=").append(data).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Where.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Where.java deleted file mode 100644 index 0a5f0b7c90..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/data/Where.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.data; - -/** - * @author David Bennett - Initial contribution - * @author Wouter Born - Extract Where object from Structure - * @author Wouter Born - Add equals, hashCode, toString methods - */ -public class Where { - private String whereId; - private String name; - - public String getWhereId() { - return whereId; - } - - public String getName() { - return name; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Where other = (Where) obj; - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (whereId == null) { - if (other.whereId != null) { - return false; - } - } else if (!whereId.equals(other.whereId)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((whereId == null) ? 0 : whereId.hashCode()); - return result; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Where [whereId=").append(whereId).append(", name=").append(name).append("]"); - return builder.toString(); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/discovery/NestDiscoveryService.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/discovery/NestDiscoveryService.java deleted file mode 100644 index 14ca64a2e4..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/discovery/NestDiscoveryService.java +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.discovery; - -import static org.openhab.binding.nest.internal.NestBindingConstants.*; -import static org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.nest.internal.config.NestDeviceConfiguration; -import org.openhab.binding.nest.internal.config.NestStructureConfiguration; -import org.openhab.binding.nest.internal.data.BaseNestDevice; -import org.openhab.binding.nest.internal.data.Camera; -import org.openhab.binding.nest.internal.data.SmokeDetector; -import org.openhab.binding.nest.internal.data.Structure; -import org.openhab.binding.nest.internal.data.Thermostat; -import org.openhab.binding.nest.internal.handler.NestBridgeHandler; -import org.openhab.binding.nest.internal.listener.NestThingDataListener; -import org.openhab.core.config.discovery.AbstractDiscoveryService; -import org.openhab.core.config.discovery.DiscoveryResultBuilder; -import org.openhab.core.thing.ThingTypeUID; -import org.openhab.core.thing.ThingUID; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This service connects to the Nest bridge and creates the correct discovery results for Nest devices - * as they are found through the API. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Add representation properties - */ -@NonNullByDefault -public class NestDiscoveryService extends AbstractDiscoveryService { - - private static final Set SUPPORTED_THING_TYPES = Stream - .of(THING_TYPE_CAMERA, THING_TYPE_THERMOSTAT, THING_TYPE_SMOKE_DETECTOR, THING_TYPE_STRUCTURE) - .collect(Collectors.toSet()); - - private final Logger logger = LoggerFactory.getLogger(NestDiscoveryService.class); - - private final DiscoveryDataListener cameraDiscoveryDataListener = new DiscoveryDataListener<>(Camera.class, - THING_TYPE_CAMERA, this::addDeviceDiscoveryResult); - private final DiscoveryDataListener smokeDetectorDiscoveryDataListener = new DiscoveryDataListener<>( - SmokeDetector.class, THING_TYPE_SMOKE_DETECTOR, this::addDeviceDiscoveryResult); - private final DiscoveryDataListener structureDiscoveryDataListener = new DiscoveryDataListener<>( - Structure.class, THING_TYPE_STRUCTURE, this::addStructureDiscoveryResult); - private final DiscoveryDataListener thermostatDiscoveryDataListener = new DiscoveryDataListener<>( - Thermostat.class, THING_TYPE_THERMOSTAT, this::addDeviceDiscoveryResult); - - @SuppressWarnings("rawtypes") - private final List discoveryDataListeners = Stream.of(cameraDiscoveryDataListener, - smokeDetectorDiscoveryDataListener, structureDiscoveryDataListener, thermostatDiscoveryDataListener) - .collect(Collectors.toList()); - - private final NestBridgeHandler bridge; - - private static class DiscoveryDataListener implements NestThingDataListener { - private Class dataClass; - private ThingTypeUID thingTypeUID; - private BiConsumer onDiscovered; - - private DiscoveryDataListener(Class dataClass, ThingTypeUID thingTypeUID, - BiConsumer onDiscovered) { - this.dataClass = dataClass; - this.thingTypeUID = thingTypeUID; - this.onDiscovered = onDiscovered; - } - - @Override - public void onNewData(T data) { - onDiscovered.accept(data, thingTypeUID); - } - - @Override - public void onUpdatedData(T oldData, T data) { - } - - @Override - public void onMissingData(String nestId) { - } - } - - public NestDiscoveryService(NestBridgeHandler bridge) { - super(SUPPORTED_THING_TYPES, 60, true); - this.bridge = bridge; - } - - @SuppressWarnings("unchecked") - public void activate() { - discoveryDataListeners.forEach(l -> bridge.addThingDataListener(l.dataClass, l)); - addDiscoveryResultsFromLastUpdates(); - } - - @Override - @SuppressWarnings("unchecked") - public void deactivate() { - discoveryDataListeners.forEach(l -> bridge.removeThingDataListener(l.dataClass, l)); - } - - @Override - protected void startScan() { - addDiscoveryResultsFromLastUpdates(); - } - - @SuppressWarnings("unchecked") - private void addDiscoveryResultsFromLastUpdates() { - discoveryDataListeners - .forEach(l -> addDiscoveryResultsFromLastUpdates(l.dataClass, l.thingTypeUID, l.onDiscovered)); - } - - private void addDiscoveryResultsFromLastUpdates(Class dataClass, ThingTypeUID thingTypeUID, - BiConsumer onDiscovered) { - List lastUpdates = bridge.getLastUpdates(dataClass); - lastUpdates.forEach(lastUpdate -> onDiscovered.accept(lastUpdate, thingTypeUID)); - } - - private void addDeviceDiscoveryResult(BaseNestDevice device, ThingTypeUID typeUID) { - ThingUID bridgeUID = bridge.getThing().getUID(); - ThingUID thingUID = new ThingUID(typeUID, bridgeUID, device.getDeviceId()); - logger.debug("Discovered {}", thingUID); - Map properties = new HashMap<>(); - properties.put(NestDeviceConfiguration.DEVICE_ID, device.getDeviceId()); - properties.put(PROPERTY_FIRMWARE_VERSION, device.getSoftwareVersion()); - // @formatter:off - thingDiscovered(DiscoveryResultBuilder.create(thingUID) - .withThingType(typeUID) - .withLabel(device.getNameLong()) - .withBridge(bridgeUID) - .withProperties(properties) - .withRepresentationProperty(NestDeviceConfiguration.DEVICE_ID) - .build() - ); - // @formatter:on - } - - public void addStructureDiscoveryResult(Structure structure, ThingTypeUID typeUID) { - ThingUID bridgeUID = bridge.getThing().getUID(); - ThingUID thingUID = new ThingUID(typeUID, bridgeUID, structure.getStructureId()); - logger.debug("Discovered {}", thingUID); - Map properties = new HashMap<>(); - properties.put(NestStructureConfiguration.STRUCTURE_ID, structure.getStructureId()); - // @formatter:off - thingDiscovered(DiscoveryResultBuilder.create(thingUID) - .withThingType(THING_TYPE_STRUCTURE) - .withLabel(structure.getName()) - .withBridge(bridgeUID) - .withProperties(properties) - .withRepresentationProperty(NestStructureConfiguration.STRUCTURE_ID) - .build() - ); - // @formatter:on - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedResolvingNestUrlException.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedResolvingNestUrlException.java deleted file mode 100644 index 23d8ed8d95..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedResolvingNestUrlException.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.exceptions; - -/** - * Will be thrown when the bridge was unable to resolve the Nest redirect URL. - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Improve exception handling while sending data - */ -@SuppressWarnings("serial") -public class FailedResolvingNestUrlException extends Exception { - public FailedResolvingNestUrlException(String message) { - super(message); - } - - public FailedResolvingNestUrlException(String message, Throwable cause) { - super(message, cause); - } - - public FailedResolvingNestUrlException(Throwable cause) { - super(cause); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedRetrievingNestDataException.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedRetrievingNestDataException.java deleted file mode 100644 index f762c3c696..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedRetrievingNestDataException.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.exceptions; - -/** - * Will be thrown when the bridge was unable to retrieve data. - * - * @author Martin van Wingerden - Initial contribution - * @author Martin van Wingerden - Added more centralized handling of failure when retrieving data - */ -@SuppressWarnings("serial") -public class FailedRetrievingNestDataException extends Exception { - - public FailedRetrievingNestDataException(String message) { - super(message); - } - - public FailedRetrievingNestDataException(String message, Throwable cause) { - super(message, cause); - } - - public FailedRetrievingNestDataException(Throwable cause) { - super(cause); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedSendingNestDataException.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedSendingNestDataException.java deleted file mode 100644 index 02627e87b3..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/FailedSendingNestDataException.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.exceptions; - -/** - * Will be thrown when the bridge was unable to send data. - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Improve exception handling while sending data - */ -@SuppressWarnings("serial") -public class FailedSendingNestDataException extends Exception { - public FailedSendingNestDataException(String message) { - super(message); - } - - public FailedSendingNestDataException(String message, Throwable cause) { - super(message, cause); - } - - public FailedSendingNestDataException(Throwable cause) { - super(cause); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/InvalidAccessTokenException.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/InvalidAccessTokenException.java deleted file mode 100644 index ea14ee6af0..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/exceptions/InvalidAccessTokenException.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.exceptions; - -/** - * Will be thrown when there is no valid access token and it was not possible to refresh it - * - * @author Martin van Wingerden - Initial contribution - * @author Martin van Wingerden - Added more centralized handling of invalid access tokens - */ -@SuppressWarnings("serial") -public class InvalidAccessTokenException extends Exception { - public InvalidAccessTokenException(Exception cause) { - super(cause); - } - - public InvalidAccessTokenException(String message, Throwable cause) { - super(message, cause); - } - - public InvalidAccessTokenException(String message) { - super(message); - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestBaseHandler.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestBaseHandler.java deleted file mode 100644 index 80b52b0ce0..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestBaseHandler.java +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.handler; - -import java.time.Instant; -import java.time.ZonedDateTime; -import java.util.Collection; -import java.util.Date; -import java.util.TimeZone; -import java.util.stream.Collectors; - -import javax.measure.Quantity; -import javax.measure.Unit; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.nest.internal.config.NestDeviceConfiguration; -import org.openhab.binding.nest.internal.data.NestIdentifiable; -import org.openhab.binding.nest.internal.listener.NestThingDataListener; -import org.openhab.binding.nest.internal.rest.NestUpdateRequest; -import org.openhab.core.library.types.DateTimeType; -import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.library.types.StringType; -import org.openhab.core.thing.Bridge; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; -import org.openhab.core.thing.ThingStatusInfo; -import org.openhab.core.thing.binding.BaseThingHandler; -import org.openhab.core.types.State; -import org.openhab.core.types.UnDefType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Deals with the structures on the Nest API, turning them into a thing in openHAB. - * - * @author David Bennett - Initial contribution - * @author Martin van Wingerden - Splitted of NestBaseHandler - * @author Wouter Born - Add generic update data type - * - * @param the type of update data - */ -@NonNullByDefault -public abstract class NestBaseHandler extends BaseThingHandler - implements NestThingDataListener, NestIdentifiable { - private final Logger logger = LoggerFactory.getLogger(NestBaseHandler.class); - - private @Nullable String deviceId; - private Class dataClass; - - NestBaseHandler(Thing thing, Class dataClass) { - super(thing); - this.dataClass = dataClass; - } - - @Override - public void initialize() { - logger.debug("Initializing handler for {}", getClass().getName()); - - NestBridgeHandler handler = getNestBridgeHandler(); - if (handler != null) { - boolean success = handler.addThingDataListener(dataClass, getId(), this); - logger.debug("Adding {} with ID '{}' as device data listener, result: {}", getClass().getSimpleName(), - getId(), success); - } else { - logger.debug("Unable to add {} with ID '{}' as device data listener because bridge is null", - getClass().getSimpleName(), getId()); - } - - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Waiting for refresh"); - - T lastUpdate = getLastUpdate(); - if (lastUpdate != null) { - update(null, lastUpdate); - } - } - - @Override - public void dispose() { - NestBridgeHandler handler = getNestBridgeHandler(); - if (handler != null) { - handler.removeThingDataListener(dataClass, getId(), this); - } - } - - protected @Nullable T getLastUpdate() { - NestBridgeHandler handler = getNestBridgeHandler(); - if (handler != null) { - return handler.getLastUpdate(dataClass, getId()); - } - return null; - } - - protected void addUpdateRequest(String updatePath, String field, Object value) { - NestBridgeHandler handler = getNestBridgeHandler(); - if (handler != null) { - // @formatter:off - handler.addUpdateRequest(new NestUpdateRequest.Builder() - .withBasePath(updatePath) - .withIdentifier(getId()) - .withAdditionalValue(field, value) - .build()); - // @formatter:on - } - } - - @Override - public String getId() { - return getDeviceId(); - } - - protected String getDeviceId() { - String localDeviceId = deviceId; - if (localDeviceId == null) { - localDeviceId = getConfigAs(NestDeviceConfiguration.class).deviceId; - deviceId = localDeviceId; - } - return localDeviceId; - } - - protected @Nullable NestBridgeHandler getNestBridgeHandler() { - Bridge bridge = getBridge(); - return bridge != null ? (NestBridgeHandler) bridge.getHandler() : null; - } - - protected abstract State getChannelState(ChannelUID channelUID, T data); - - protected State getAsDateTimeTypeOrNull(@Nullable Date date) { - if (date == null) { - return UnDefType.NULL; - } - - long offsetMillis = TimeZone.getDefault().getOffset(date.getTime()); - Instant instant = date.toInstant().plusMillis(offsetMillis); - return new DateTimeType(ZonedDateTime.ofInstant(instant, TimeZone.getDefault().toZoneId())); - } - - protected State getAsDecimalTypeOrNull(@Nullable Integer value) { - return value == null ? UnDefType.NULL : new DecimalType(value); - } - - protected State getAsOnOffTypeOrNull(@Nullable Boolean value) { - return value == null ? UnDefType.NULL : value ? OnOffType.ON : OnOffType.OFF; - } - - protected > State getAsQuantityTypeOrNull(@Nullable Number value, Unit unit) { - return value == null ? UnDefType.NULL : new QuantityType<>(value, unit); - } - - protected State getAsStringTypeOrNull(@Nullable Object value) { - return value == null ? UnDefType.NULL : new StringType(value.toString()); - } - - protected State getAsStringTypeListOrNull(@Nullable Collection values) { - return values == null || values.isEmpty() ? UnDefType.NULL - : new StringType(values.stream().map(v -> v.toString()).collect(Collectors.joining(","))); - } - - protected boolean isNotHandling(NestIdentifiable nestIdentifiable) { - return !(getId().equals(nestIdentifiable.getId())); - } - - protected void updateLinkedChannels(T oldData, T data) { - getThing().getChannels().stream().map(c -> c.getUID()).filter(this::isLinked).forEach(channelUID -> { - State newState = getChannelState(channelUID, data); - if (oldData == null || !getChannelState(channelUID, oldData).equals(newState)) { - logger.debug("Updating {}", channelUID); - updateState(channelUID, newState); - } - }); - } - - @Override - public void onNewData(T data) { - update(null, data); - } - - @Override - public void onUpdatedData(T oldData, T data) { - update(oldData, data); - } - - @Override - public void onMissingData(String nestId) { - thing.setStatusInfo( - new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "Missing from streaming updates")); - } - - protected abstract void update(T oldData, T data); -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestBridgeHandler.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestBridgeHandler.java deleted file mode 100644 index 813877c78c..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestBridgeHandler.java +++ /dev/null @@ -1,383 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.handler; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.openhab.binding.nest.internal.NestBindingConstants.JSON_CONTENT_TYPE; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.client.ClientBuilder; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.nest.internal.NestUtils; -import org.openhab.binding.nest.internal.config.NestBridgeConfiguration; -import org.openhab.binding.nest.internal.data.ErrorData; -import org.openhab.binding.nest.internal.data.NestIdentifiable; -import org.openhab.binding.nest.internal.data.TopLevelData; -import org.openhab.binding.nest.internal.exceptions.FailedResolvingNestUrlException; -import org.openhab.binding.nest.internal.exceptions.FailedSendingNestDataException; -import org.openhab.binding.nest.internal.exceptions.InvalidAccessTokenException; -import org.openhab.binding.nest.internal.listener.NestStreamingDataListener; -import org.openhab.binding.nest.internal.listener.NestThingDataListener; -import org.openhab.binding.nest.internal.rest.NestAuthorizer; -import org.openhab.binding.nest.internal.rest.NestStreamingRestClient; -import org.openhab.binding.nest.internal.rest.NestUpdateRequest; -import org.openhab.binding.nest.internal.update.NestCompositeUpdateHandler; -import org.openhab.core.config.core.Configuration; -import org.openhab.core.io.net.http.HttpUtil; -import org.openhab.core.thing.Bridge; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.thing.ThingStatusDetail; -import org.openhab.core.thing.binding.BaseBridgeHandler; -import org.openhab.core.thing.binding.ThingHandler; -import org.openhab.core.types.Command; -import org.openhab.core.types.RefreshType; -import org.osgi.service.jaxrs.client.SseEventSourceFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This bridge handler connects to Nest and handles all the API requests. It pulls down the - * updated data, polls the system and does all the co-ordination with the other handlers - * to get the data updated to the correct things. - * - * @author David Bennett - Initial contribution - * @author Martin van Wingerden - Use listeners not only for discovery but for all data processing - * @author Wouter Born - Improve exception and URL redirect handling - */ -@NonNullByDefault -public class NestBridgeHandler extends BaseBridgeHandler implements NestStreamingDataListener { - - private static final int REQUEST_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(30); - - private final Logger logger = LoggerFactory.getLogger(NestBridgeHandler.class); - - private final ClientBuilder clientBuilder; - private final SseEventSourceFactory eventSourceFactory; - private final List nestUpdateRequests = new CopyOnWriteArrayList<>(); - private final NestCompositeUpdateHandler updateHandler = new NestCompositeUpdateHandler( - this::getPresentThingsNestIds); - - private @NonNullByDefault({}) NestAuthorizer authorizer; - private @NonNullByDefault({}) NestBridgeConfiguration config; - - private @Nullable ScheduledFuture initializeJob; - private @Nullable ScheduledFuture transmitJob; - private @Nullable NestRedirectUrlSupplier redirectUrlSupplier; - private @Nullable NestStreamingRestClient streamingRestClient; - - /** - * Creates the bridge handler to connect to Nest. - * - * @param bridge The bridge to connect to Nest with. - */ - public NestBridgeHandler(Bridge bridge, ClientBuilder clientBuilder, SseEventSourceFactory eventSourceFactory) { - super(bridge); - this.clientBuilder = clientBuilder; - this.eventSourceFactory = eventSourceFactory; - } - - /** - * Initialize the connection to Nest. - */ - @Override - public void initialize() { - logger.debug("Initializing Nest bridge handler"); - - config = getConfigAs(NestBridgeConfiguration.class); - authorizer = new NestAuthorizer(config); - updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Starting poll query"); - - initializeJob = scheduler.schedule(() -> { - try { - logger.debug("Product ID {}", config.productId); - logger.debug("Product Secret {}", config.productSecret); - logger.debug("Pincode {}", config.pincode); - logger.debug("Access Token {}", getExistingOrNewAccessToken()); - redirectUrlSupplier = createRedirectUrlSupplier(); - restartStreamingUpdates(); - } catch (InvalidAccessTokenException e) { - logger.debug("Invalid access token", e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Token is invalid and could not be refreshed: " + e.getMessage()); - } - }, 0, TimeUnit.SECONDS); - - logger.debug("Finished initializing Nest bridge handler"); - } - - /** - * Clean up the handler. - */ - @Override - public void dispose() { - logger.debug("Nest bridge disposed"); - stopStreamingUpdates(); - - ScheduledFuture localInitializeJob = initializeJob; - if (localInitializeJob != null && !localInitializeJob.isCancelled()) { - localInitializeJob.cancel(true); - initializeJob = null; - } - - ScheduledFuture localTransmitJob = transmitJob; - if (localTransmitJob != null && !localTransmitJob.isCancelled()) { - localTransmitJob.cancel(true); - transmitJob = null; - } - - this.authorizer = null; - this.redirectUrlSupplier = null; - this.streamingRestClient = null; - } - - public boolean addThingDataListener(Class dataClass, NestThingDataListener listener) { - return updateHandler.addListener(dataClass, listener); - } - - public boolean addThingDataListener(Class dataClass, String nestId, NestThingDataListener listener) { - return updateHandler.addListener(dataClass, nestId, listener); - } - - /** - * Adds the update request into the queue for doing something with, send immediately if the queue is empty. - */ - public void addUpdateRequest(NestUpdateRequest request) { - nestUpdateRequests.add(request); - scheduleTransmitJobForPendingRequests(); - } - - protected NestRedirectUrlSupplier createRedirectUrlSupplier() throws InvalidAccessTokenException { - return new NestRedirectUrlSupplier(getHttpHeaders()); - } - - private String getExistingOrNewAccessToken() throws InvalidAccessTokenException { - String accessToken = config.accessToken; - if (accessToken == null || accessToken.isEmpty()) { - accessToken = authorizer.getNewAccessToken(); - config.accessToken = accessToken; - config.pincode = ""; - // Update and save the access token in the bridge configuration - Configuration configuration = editConfiguration(); - configuration.put(NestBridgeConfiguration.ACCESS_TOKEN, config.accessToken); - configuration.put(NestBridgeConfiguration.PINCODE, config.pincode); - updateConfiguration(configuration); - logger.debug("Retrieved new access token: {}", config.accessToken); - return accessToken; - } else { - logger.debug("Re-using access token from configuration: {}", accessToken); - return accessToken; - } - } - - protected Properties getHttpHeaders() throws InvalidAccessTokenException { - Properties httpHeaders = new Properties(); - httpHeaders.put("Authorization", "Bearer " + getExistingOrNewAccessToken()); - httpHeaders.put("Content-Type", JSON_CONTENT_TYPE); - return httpHeaders; - } - - public @Nullable T getLastUpdate(Class dataClass, String nestId) { - return updateHandler.getLastUpdate(dataClass, nestId); - } - - public List getLastUpdates(Class dataClass) { - return updateHandler.getLastUpdates(dataClass); - } - - private NestRedirectUrlSupplier getOrCreateRedirectUrlSupplier() throws InvalidAccessTokenException { - NestRedirectUrlSupplier localRedirectUrlSupplier = redirectUrlSupplier; - if (localRedirectUrlSupplier == null) { - localRedirectUrlSupplier = createRedirectUrlSupplier(); - redirectUrlSupplier = localRedirectUrlSupplier; - } - return localRedirectUrlSupplier; - } - - private Set getPresentThingsNestIds() { - Set nestIds = new HashSet<>(); - for (Thing thing : getThing().getThings()) { - ThingHandler handler = thing.getHandler(); - if (handler != null && thing.getStatusInfo().getStatusDetail() != ThingStatusDetail.GONE) { - nestIds.add(((NestIdentifiable) handler).getId()); - } - } - return nestIds; - } - - /** - * Handles an incoming command update - */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - if (command instanceof RefreshType) { - logger.debug("Refresh command received"); - updateHandler.resendLastUpdates(); - } - } - - private void jsonToPutUrl(NestUpdateRequest request) - throws FailedSendingNestDataException, InvalidAccessTokenException, FailedResolvingNestUrlException { - try { - NestRedirectUrlSupplier localRedirectUrlSupplier = redirectUrlSupplier; - if (localRedirectUrlSupplier == null) { - throw new FailedResolvingNestUrlException("redirectUrlSupplier is null"); - } - - String url = localRedirectUrlSupplier.getRedirectUrl() + request.getUpdatePath(); - logger.debug("Putting data to: {}", url); - - String jsonContent = NestUtils.toJson(request.getValues()); - logger.debug("PUT content: {}", jsonContent); - - ByteArrayInputStream inputStream = new ByteArrayInputStream(jsonContent.getBytes(StandardCharsets.UTF_8)); - String jsonResponse = HttpUtil.executeUrl("PUT", url, getHttpHeaders(), inputStream, JSON_CONTENT_TYPE, - REQUEST_TIMEOUT); - logger.debug("PUT response: {}", jsonResponse); - - ErrorData error = NestUtils.fromJson(jsonResponse, ErrorData.class); - if (error.getError() != null && !error.getError().isBlank()) { - logger.debug("Nest API error: {}", error); - logger.warn("Nest API error: {}", error.getMessage()); - } - } catch (IOException e) { - throw new FailedSendingNestDataException("Failed to send data", e); - } - } - - @Override - public void onAuthorizationRevoked(String token) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Authorization token revoked: " + token); - } - - @Override - public void onConnected() { - updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "Streaming data connection established"); - scheduleTransmitJobForPendingRequests(); - } - - @Override - public void onDisconnected() { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Streaming data disconnected"); - } - - @Override - public void onError(String message) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message); - } - - @Override - public void onNewTopLevelData(TopLevelData data) { - updateHandler.handleUpdate(data); - updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "Receiving streaming data"); - } - - public boolean removeThingDataListener(Class dataClass, NestThingDataListener listener) { - return updateHandler.removeListener(dataClass, listener); - } - - public boolean removeThingDataListener(Class dataClass, String nestId, NestThingDataListener listener) { - return updateHandler.removeListener(dataClass, nestId, listener); - } - - private void restartStreamingUpdates() { - synchronized (this) { - stopStreamingUpdates(); - startStreamingUpdates(); - } - } - - private void scheduleTransmitJobForPendingRequests() { - ScheduledFuture localTransmitJob = transmitJob; - if (!nestUpdateRequests.isEmpty() && (localTransmitJob == null || localTransmitJob.isDone())) { - transmitJob = scheduler.schedule(this::transmitQueue, 0, SECONDS); - } - } - - private void startStreamingUpdates() { - synchronized (this) { - try { - NestStreamingRestClient localStreamingRestClient = new NestStreamingRestClient( - getExistingOrNewAccessToken(), clientBuilder, eventSourceFactory, - getOrCreateRedirectUrlSupplier(), scheduler); - localStreamingRestClient.addStreamingDataListener(this); - localStreamingRestClient.start(); - - streamingRestClient = localStreamingRestClient; - } catch (InvalidAccessTokenException e) { - logger.debug("Invalid access token", e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Token is invalid and could not be refreshed: " + e.getMessage()); - } - } - } - - private void stopStreamingUpdates() { - NestStreamingRestClient localStreamingRestClient = streamingRestClient; - if (localStreamingRestClient != null) { - synchronized (this) { - localStreamingRestClient.stop(); - localStreamingRestClient.removeStreamingDataListener(this); - streamingRestClient = null; - } - } - } - - private void transmitQueue() { - if (getThing().getStatus() == ThingStatus.OFFLINE) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, - "Not transmitting events because bridge is OFFLINE"); - return; - } - - try { - while (!nestUpdateRequests.isEmpty()) { - // nestUpdateRequests is a CopyOnWriteArrayList so its iterator does not support remove operations - NestUpdateRequest request = nestUpdateRequests.get(0); - jsonToPutUrl(request); - nestUpdateRequests.remove(request); - } - } catch (InvalidAccessTokenException e) { - logger.debug("Invalid access token", e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "Token is invalid and could not be refreshed: " + e.getMessage()); - } catch (FailedResolvingNestUrlException e) { - logger.debug("Unable to resolve redirect URL", e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); - scheduler.schedule(this::restartStreamingUpdates, 5, SECONDS); - } catch (FailedSendingNestDataException e) { - logger.debug("Error sending data", e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); - scheduler.schedule(this::restartStreamingUpdates, 5, SECONDS); - - NestRedirectUrlSupplier localRedirectUrlSupplier = redirectUrlSupplier; - if (localRedirectUrlSupplier != null) { - localRedirectUrlSupplier.resetCache(); - } - } - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestCameraHandler.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestCameraHandler.java deleted file mode 100644 index 0c2534b96c..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestCameraHandler.java +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.handler; - -import static org.openhab.binding.nest.internal.NestBindingConstants.*; -import static org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION; -import static org.openhab.core.types.RefreshType.REFRESH; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.nest.internal.data.Camera; -import org.openhab.binding.nest.internal.data.CameraEvent; -import org.openhab.core.library.types.OnOffType; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.types.Command; -import org.openhab.core.types.State; -import org.openhab.core.types.UnDefType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Handles all the updates to the camera as well as handling the commands that send - * updates to Nest. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Handle channel refresh command - */ -@NonNullByDefault -public class NestCameraHandler extends NestBaseHandler { - private final Logger logger = LoggerFactory.getLogger(NestCameraHandler.class); - - public NestCameraHandler(Thing thing) { - super(thing, Camera.class); - } - - @Override - protected State getChannelState(ChannelUID channelUID, Camera camera) { - if (channelUID.getId().startsWith(CHANNEL_GROUP_CAMERA_PREFIX)) { - return getCameraChannelState(channelUID, camera); - } else if (channelUID.getId().startsWith(CHANNEL_GROUP_LAST_EVENT_PREFIX)) { - return getLastEventChannelState(channelUID, camera); - } else { - logger.error("Unsupported channelId '{}'", channelUID.getId()); - return UnDefType.UNDEF; - } - } - - protected State getCameraChannelState(ChannelUID channelUID, Camera camera) { - switch (channelUID.getId()) { - case CHANNEL_CAMERA_APP_URL: - return getAsStringTypeOrNull(camera.getAppUrl()); - case CHANNEL_CAMERA_AUDIO_INPUT_ENABLED: - return getAsOnOffTypeOrNull(camera.isAudioInputEnabled()); - case CHANNEL_CAMERA_LAST_ONLINE_CHANGE: - return getAsDateTimeTypeOrNull(camera.getLastIsOnlineChange()); - case CHANNEL_CAMERA_PUBLIC_SHARE_ENABLED: - return getAsOnOffTypeOrNull(camera.isPublicShareEnabled()); - case CHANNEL_CAMERA_PUBLIC_SHARE_URL: - return getAsStringTypeOrNull(camera.getPublicShareUrl()); - case CHANNEL_CAMERA_SNAPSHOT_URL: - return getAsStringTypeOrNull(camera.getSnapshotUrl()); - case CHANNEL_CAMERA_STREAMING: - return getAsOnOffTypeOrNull(camera.isStreaming()); - case CHANNEL_CAMERA_VIDEO_HISTORY_ENABLED: - return getAsOnOffTypeOrNull(camera.isVideoHistoryEnabled()); - case CHANNEL_CAMERA_WEB_URL: - return getAsStringTypeOrNull(camera.getWebUrl()); - default: - logger.error("Unsupported channelId '{}'", channelUID.getId()); - return UnDefType.UNDEF; - } - } - - protected State getLastEventChannelState(ChannelUID channelUID, Camera camera) { - CameraEvent lastEvent = camera.getLastEvent(); - if (lastEvent == null) { - return UnDefType.NULL; - } - - switch (channelUID.getId()) { - case CHANNEL_LAST_EVENT_ACTIVITY_ZONES: - return getAsStringTypeListOrNull(lastEvent.getActivityZones()); - case CHANNEL_LAST_EVENT_ANIMATED_IMAGE_URL: - return getAsStringTypeOrNull(lastEvent.getAnimatedImageUrl()); - case CHANNEL_LAST_EVENT_APP_URL: - return getAsStringTypeOrNull(lastEvent.getAppUrl()); - case CHANNEL_LAST_EVENT_END_TIME: - return getAsDateTimeTypeOrNull(lastEvent.getEndTime()); - case CHANNEL_LAST_EVENT_HAS_MOTION: - return getAsOnOffTypeOrNull(lastEvent.isHasMotion()); - case CHANNEL_LAST_EVENT_HAS_PERSON: - return getAsOnOffTypeOrNull(lastEvent.isHasPerson()); - case CHANNEL_LAST_EVENT_HAS_SOUND: - return getAsOnOffTypeOrNull(lastEvent.isHasSound()); - case CHANNEL_LAST_EVENT_IMAGE_URL: - return getAsStringTypeOrNull(lastEvent.getImageUrl()); - case CHANNEL_LAST_EVENT_START_TIME: - return getAsDateTimeTypeOrNull(lastEvent.getStartTime()); - case CHANNEL_LAST_EVENT_URLS_EXPIRE_TIME: - return getAsDateTimeTypeOrNull(lastEvent.getUrlsExpireTime()); - case CHANNEL_LAST_EVENT_WEB_URL: - return getAsStringTypeOrNull(lastEvent.getWebUrl()); - default: - logger.error("Unsupported channelId '{}'", channelUID.getId()); - return UnDefType.UNDEF; - } - } - - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - if (REFRESH.equals(command)) { - Camera lastUpdate = getLastUpdate(); - if (lastUpdate != null) { - updateState(channelUID, getChannelState(channelUID, lastUpdate)); - } - } else if (CHANNEL_CAMERA_STREAMING.equals(channelUID.getId())) { - // Change the mode. - if (command instanceof OnOffType) { - // Set the mode to be the cmd value. - addUpdateRequest("is_streaming", command == OnOffType.ON); - } - } - } - - private void addUpdateRequest(String field, Object value) { - addUpdateRequest(NEST_CAMERA_UPDATE_PATH, field, value); - } - - @Override - protected void update(Camera oldCamera, Camera camera) { - logger.debug("Updating {}", getThing().getUID()); - - updateLinkedChannels(oldCamera, camera); - updateProperty(PROPERTY_FIRMWARE_VERSION, camera.getSoftwareVersion()); - - ThingStatus newStatus = camera.isOnline() == null ? ThingStatus.UNKNOWN - : camera.isOnline() ? ThingStatus.ONLINE : ThingStatus.OFFLINE; - if (newStatus != thing.getStatus()) { - updateStatus(newStatus); - } - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestRedirectUrlSupplier.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestRedirectUrlSupplier.java deleted file mode 100644 index 90d08da70d..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestRedirectUrlSupplier.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.handler; - -import java.util.Properties; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.openhab.binding.nest.internal.NestBindingConstants; -import org.openhab.binding.nest.internal.exceptions.FailedResolvingNestUrlException; -import org.openhab.core.io.net.http.HttpUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Supplies resolved redirect URLs of {@link NestBindingConstants#NEST_URL} so they can be used with HTTP clients that - * do not pass Authorization headers after redirects like the Jetty client used by {@link HttpUtil}. - * - * @author Wouter Born - Initial contribution - * @author Wouter Born - Extract resolving redirect URL from NestBridgeHandler into NestRedirectUrlSupplier - */ -@NonNullByDefault -public class NestRedirectUrlSupplier { - - private final Logger logger = LoggerFactory.getLogger(NestRedirectUrlSupplier.class); - - protected String cachedUrl = ""; - - protected Properties httpHeaders; - - public NestRedirectUrlSupplier(Properties httpHeaders) { - this.httpHeaders = httpHeaders; - } - - public String getRedirectUrl() throws FailedResolvingNestUrlException { - if (cachedUrl.isEmpty()) { - cachedUrl = resolveRedirectUrl(); - } - return cachedUrl; - } - - public void resetCache() { - cachedUrl = ""; - } - - /** - * Resolves the redirect URL for calls using the {@link NestBindingConstants#NEST_URL}. - * - * The Jetty client used by {@link HttpUtil} will not pass the Authorization header after a redirect resulting in - * "401 Unauthorized error" issues. - * - * Note that this workaround currently does not use any configured proxy like {@link HttpUtil} does. - * - * @see https://developers.nest.com/documentation/cloud/how-to-handle-redirects - */ - private String resolveRedirectUrl() throws FailedResolvingNestUrlException { - HttpClient httpClient = new HttpClient(new SslContextFactory.Client()); - httpClient.setFollowRedirects(false); - - Request request = httpClient.newRequest(NestBindingConstants.NEST_URL).method(HttpMethod.GET).timeout(30, - TimeUnit.SECONDS); - for (String httpHeaderKey : httpHeaders.stringPropertyNames()) { - request.header(httpHeaderKey, httpHeaders.getProperty(httpHeaderKey)); - } - - ContentResponse response; - try { - httpClient.start(); - response = request.send(); - httpClient.stop(); - } catch (Exception e) { - throw new FailedResolvingNestUrlException("Failed to resolve redirect URL: " + e.getMessage(), e); - } - - int status = response.getStatus(); - String redirectUrl = response.getHeaders().get(HttpHeader.LOCATION); - - if (status != HttpStatus.TEMPORARY_REDIRECT_307) { - logger.debug("Redirect status: {}", status); - logger.debug("Redirect response: {}", response.getContentAsString()); - throw new FailedResolvingNestUrlException("Failed to get redirect URL, expected status " - + HttpStatus.TEMPORARY_REDIRECT_307 + " but was " + status); - } else if (redirectUrl == null || redirectUrl.isEmpty()) { - throw new FailedResolvingNestUrlException("Redirect URL is empty"); - } - - redirectUrl = redirectUrl.endsWith("/") ? redirectUrl.substring(0, redirectUrl.length() - 1) : redirectUrl; - logger.debug("Redirect URL: {}", redirectUrl); - return redirectUrl; - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestSmokeDetectorHandler.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestSmokeDetectorHandler.java deleted file mode 100644 index dc85a485b0..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestSmokeDetectorHandler.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.handler; - -import static org.openhab.binding.nest.internal.NestBindingConstants.*; -import static org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION; -import static org.openhab.core.types.RefreshType.REFRESH; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.nest.internal.data.SmokeDetector; -import org.openhab.binding.nest.internal.data.SmokeDetector.BatteryHealth; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.types.Command; -import org.openhab.core.types.State; -import org.openhab.core.types.UnDefType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The smoke detector handler, it handles the data from Nest for the smoke detector. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Handle channel refresh command - */ -@NonNullByDefault -public class NestSmokeDetectorHandler extends NestBaseHandler { - private final Logger logger = LoggerFactory.getLogger(NestSmokeDetectorHandler.class); - - public NestSmokeDetectorHandler(Thing thing) { - super(thing, SmokeDetector.class); - } - - @Override - protected State getChannelState(ChannelUID channelUID, SmokeDetector smokeDetector) { - switch (channelUID.getId()) { - case CHANNEL_CO_ALARM_STATE: - return getAsStringTypeOrNull(smokeDetector.getCoAlarmState()); - case CHANNEL_LAST_CONNECTION: - return getAsDateTimeTypeOrNull(smokeDetector.getLastConnection()); - case CHANNEL_LAST_MANUAL_TEST_TIME: - return getAsDateTimeTypeOrNull(smokeDetector.getLastManualTestTime()); - case CHANNEL_LOW_BATTERY: - return getAsOnOffTypeOrNull(smokeDetector.getBatteryHealth() == null ? null - : smokeDetector.getBatteryHealth() == BatteryHealth.REPLACE); - case CHANNEL_MANUAL_TEST_ACTIVE: - return getAsOnOffTypeOrNull(smokeDetector.isManualTestActive()); - case CHANNEL_SMOKE_ALARM_STATE: - return getAsStringTypeOrNull(smokeDetector.getSmokeAlarmState()); - case CHANNEL_UI_COLOR_STATE: - return getAsStringTypeOrNull(smokeDetector.getUiColorState()); - default: - logger.error("Unsupported channelId '{}'", channelUID.getId()); - return UnDefType.UNDEF; - } - } - - /** - * Handles any incoming command requests. - */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - if (REFRESH.equals(command)) { - SmokeDetector lastUpdate = getLastUpdate(); - if (lastUpdate != null) { - updateState(channelUID, getChannelState(channelUID, lastUpdate)); - } - } - } - - @Override - protected void update(SmokeDetector oldSmokeDetector, SmokeDetector smokeDetector) { - logger.debug("Updating {}", getThing().getUID()); - - updateLinkedChannels(oldSmokeDetector, smokeDetector); - updateProperty(PROPERTY_FIRMWARE_VERSION, smokeDetector.getSoftwareVersion()); - - ThingStatus newStatus = smokeDetector.isOnline() == null ? ThingStatus.UNKNOWN - : smokeDetector.isOnline() ? ThingStatus.ONLINE : ThingStatus.OFFLINE; - if (newStatus != thing.getStatus()) { - updateStatus(newStatus); - } - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestStructureHandler.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestStructureHandler.java deleted file mode 100644 index e77cdc6a89..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestStructureHandler.java +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.handler; - -import static org.openhab.binding.nest.internal.NestBindingConstants.*; -import static org.openhab.core.types.RefreshType.REFRESH; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.nest.internal.config.NestStructureConfiguration; -import org.openhab.binding.nest.internal.data.Structure; -import org.openhab.binding.nest.internal.data.Structure.HomeAwayState; -import org.openhab.core.library.types.StringType; -import org.openhab.core.thing.ChannelUID; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.types.Command; -import org.openhab.core.types.State; -import org.openhab.core.types.UnDefType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Deals with the structures on the Nest API, turning them into a thing in openHAB. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Handle channel refresh command - */ -@NonNullByDefault -public class NestStructureHandler extends NestBaseHandler { - private final Logger logger = LoggerFactory.getLogger(NestStructureHandler.class); - - private @Nullable String structureId; - - public NestStructureHandler(Thing thing) { - super(thing, Structure.class); - } - - @Override - protected State getChannelState(ChannelUID channelUID, Structure structure) { - switch (channelUID.getId()) { - case CHANNEL_AWAY: - return getAsStringTypeOrNull(structure.getAway()); - case CHANNEL_CO_ALARM_STATE: - return getAsStringTypeOrNull(structure.getCoAlarmState()); - case CHANNEL_COUNTRY_CODE: - return getAsStringTypeOrNull(structure.getCountryCode()); - case CHANNEL_ETA_BEGIN: - return getAsDateTimeTypeOrNull(structure.getEtaBegin()); - case CHANNEL_PEAK_PERIOD_END_TIME: - return getAsDateTimeTypeOrNull(structure.getPeakPeriodEndTime()); - case CHANNEL_PEAK_PERIOD_START_TIME: - return getAsDateTimeTypeOrNull(structure.getPeakPeriodStartTime()); - case CHANNEL_POSTAL_CODE: - return getAsStringTypeOrNull(structure.getPostalCode()); - case CHANNEL_RUSH_HOUR_REWARDS_ENROLLMENT: - return getAsOnOffTypeOrNull(structure.isRhrEnrollment()); - case CHANNEL_SECURITY_STATE: - return getAsStringTypeOrNull(structure.getWwnSecurityState()); - case CHANNEL_SMOKE_ALARM_STATE: - return getAsStringTypeOrNull(structure.getSmokeAlarmState()); - case CHANNEL_TIME_ZONE: - return getAsStringTypeOrNull(structure.getTimeZone()); - default: - logger.error("Unsupported channelId '{}'", channelUID.getId()); - return UnDefType.UNDEF; - } - } - - @Override - public String getId() { - return getStructureId(); - } - - private String getStructureId() { - String localStructureId = structureId; - if (localStructureId == null) { - localStructureId = getConfigAs(NestStructureConfiguration.class).structureId; - structureId = localStructureId; - } - return localStructureId; - } - - /** - * Handles updating the details on this structure by sending the request all the way - * to Nest. - * - * @param channelUID the channel to update - * @param command the command to apply - */ - @Override - public void handleCommand(ChannelUID channelUID, Command command) { - if (REFRESH.equals(command)) { - Structure lastUpdate = getLastUpdate(); - if (lastUpdate != null) { - updateState(channelUID, getChannelState(channelUID, lastUpdate)); - } - } else if (CHANNEL_AWAY.equals(channelUID.getId())) { - // Change the home/away state. - if (command instanceof StringType) { - StringType cmd = (StringType) command; - // Set the mode to be the cmd value. - addUpdateRequest(NEST_STRUCTURE_UPDATE_PATH, "away", HomeAwayState.valueOf(cmd.toString())); - } - } - } - - @Override - protected void update(Structure oldStructure, Structure structure) { - logger.debug("Updating {}", getThing().getUID()); - - updateLinkedChannels(oldStructure, structure); - - if (ThingStatus.ONLINE != thing.getStatus()) { - updateStatus(ThingStatus.ONLINE); - } - } -} diff --git a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestThermostatHandler.java b/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestThermostatHandler.java deleted file mode 100644 index 41d9b9470e..0000000000 --- a/bundles/org.openhab.binding.nest/src/main/java/org/openhab/binding/nest/internal/handler/NestThermostatHandler.java +++ /dev/null @@ -1,219 +0,0 @@ -/** - * Copyright (c) 2010-2021 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.nest.internal.handler; - -import static org.openhab.binding.nest.internal.NestBindingConstants.*; -import static org.openhab.core.library.unit.SIUnits.CELSIUS; -import static org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION; -import static org.openhab.core.types.RefreshType.REFRESH; - -import java.math.BigDecimal; -import java.math.RoundingMode; - -import javax.measure.Unit; -import javax.measure.quantity.Temperature; -import javax.measure.quantity.Time; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.nest.internal.data.Thermostat; -import org.openhab.binding.nest.internal.data.Thermostat.Mode; -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.ChannelUID; -import org.openhab.core.thing.Thing; -import org.openhab.core.thing.ThingStatus; -import org.openhab.core.types.Command; -import org.openhab.core.types.State; -import org.openhab.core.types.UnDefType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The {@link NestThermostatHandler} is responsible for handling commands, which are - * sent to one of the channels for the thermostat. - * - * @author David Bennett - Initial contribution - * @author Wouter Born - Handle channel refresh command - */ -@NonNullByDefault -public class NestThermostatHandler extends NestBaseHandler { - private final Logger logger = LoggerFactory.getLogger(NestThermostatHandler.class); - - public NestThermostatHandler(Thing thing) { - super(thing, Thermostat.class); - } - - @Override - protected State getChannelState(ChannelUID channelUID, Thermostat thermostat) { - switch (channelUID.getId()) { - case CHANNEL_CAN_COOL: - return getAsOnOffTypeOrNull(thermostat.isCanCool()); - case CHANNEL_CAN_HEAT: - return getAsOnOffTypeOrNull(thermostat.isCanHeat()); - case CHANNEL_ECO_MAX_SET_POINT: - return getAsQuantityTypeOrNull(thermostat.getEcoTemperatureHigh(), thermostat.getTemperatureUnit()); - case CHANNEL_ECO_MIN_SET_POINT: - return getAsQuantityTypeOrNull(thermostat.getEcoTemperatureLow(), thermostat.getTemperatureUnit()); - case CHANNEL_FAN_TIMER_ACTIVE: - return getAsOnOffTypeOrNull(thermostat.isFanTimerActive()); - case CHANNEL_FAN_TIMER_DURATION: - return getAsQuantityTypeOrNull(thermostat.getFanTimerDuration(), Units.MINUTE); - case CHANNEL_FAN_TIMER_TIMEOUT: - return getAsDateTimeTypeOrNull(thermostat.getFanTimerTimeout()); - case CHANNEL_HAS_FAN: - return getAsOnOffTypeOrNull(thermostat.isHasFan()); - case CHANNEL_HAS_LEAF: - return getAsOnOffTypeOrNull(thermostat.isHasLeaf()); - case CHANNEL_HUMIDITY: - return getAsQuantityTypeOrNull(thermostat.getHumidity(), Units.PERCENT); - case CHANNEL_LAST_CONNECTION: - return getAsDateTimeTypeOrNull(thermostat.getLastConnection()); - case CHANNEL_LOCKED: - return getAsOnOffTypeOrNull(thermostat.isLocked()); - case CHANNEL_LOCKED_MAX_SET_POINT: - return getAsQuantityTypeOrNull(thermostat.getLockedTempMax(), thermostat.getTemperatureUnit()); - case CHANNEL_LOCKED_MIN_SET_POINT: - return getAsQuantityTypeOrNull(thermostat.getLockedTempMin(), thermostat.getTemperatureUnit()); - case CHANNEL_MAX_SET_POINT: - return getAsQuantityTypeOrNull(thermostat.getTargetTemperatureHigh(), thermostat.getTemperatureUnit()); - case CHANNEL_MIN_SET_POINT: - return getAsQuantityTypeOrNull(thermostat.getTargetTemperatureLow(), thermostat.getTemperatureUnit()); - case CHANNEL_MODE: - return getAsStringTypeOrNull(thermostat.getMode()); - case CHANNEL_PREVIOUS_MODE: - Mode previousMode = thermostat.getPreviousHvacMode() != null ? thermostat.getPreviousHvacMode() - : thermostat.getMode(); - return getAsStringTypeOrNull(previousMode); - case CHANNEL_STATE: - return getAsStringTypeOrNull(thermostat.getHvacState()); - case CHANNEL_SET_POINT: - return getAsQuantityTypeOrNull(thermostat.getTargetTemperature(), thermostat.getTemperatureUnit()); - case CHANNEL_SUNLIGHT_CORRECTION_ACTIVE: - return getAsOnOffTypeOrNull(thermostat.isSunlightCorrectionActive()); - case CHANNEL_SUNLIGHT_CORRECTION_ENABLED: - return getAsOnOffTypeOrNull(thermostat.isSunlightCorrectionEnabled()); - case CHANNEL_TEMPERATURE: - return getAsQuantityTypeOrNull(thermostat.getAmbientTemperature(), thermostat.getTemperatureUnit()); - case CHANNEL_TIME_TO_TARGET: - return getAsQuantityTypeOrNull(thermostat.getTimeToTarget(), Units.MINUTE); - case CHANNEL_USING_EMERGENCY_HEAT: - return getAsOnOffTypeOrNull(thermostat.isUsingEmergencyHeat()); - default: - logger.error("Unsupported channelId '{}'", channelUID.getId()); - return UnDefType.UNDEF; - } - } - - /** - * Handle the command to do things to the thermostat, this will change the - * value of a channel by sending the request to Nest. - */ - @Override - @SuppressWarnings("unchecked") - public void handleCommand(ChannelUID channelUID, Command command) { - if (REFRESH.equals(command)) { - Thermostat lastUpdate = getLastUpdate(); - if (lastUpdate != null) { - updateState(channelUID, getChannelState(channelUID, lastUpdate)); - } - } else if (CHANNEL_FAN_TIMER_ACTIVE.equals(channelUID.getId())) { - if (command instanceof OnOffType) { - // Update fan timer active to the command value - addUpdateRequest("fan_timer_active", command == OnOffType.ON); - } - } else if (CHANNEL_FAN_TIMER_DURATION.equals(channelUID.getId())) { - if (command instanceof QuantityType) { - // Update fan timer duration to the command value - QuantityType