From 732d7df4d793967677059cd203154e9cbf4997ca Mon Sep 17 00:00:00 2001 From: Renee Vandervelde Date: Sun, 19 Jul 2020 09:07:59 -0500 Subject: [PATCH] Handle null brightness on light states. Turns out light states can be null, for example in cases where a room is empty. This is handled without an API break by defaulting the brightness to 0 or 100% depending on the current light on/off state. --- CHANGELOG.md | 13 ++++++ .../shade/groups/ShadeGroupsModule.kt | 8 +++- .../shade/lights/HueLightStateTransformer.kt | 40 +++++++++++++++++++ .../shade/lights/HueLightsApi.kt | 26 +++++++++++- .../shade/lights/ShadeLightsModule.kt | 17 +++++--- 5 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 lights/src/main/kotlin/inkapplications/shade/lights/HueLightStateTransformer.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fe75021..c10f4b83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ Change Log ========== +1.1.1 +----- + +### Fixed: + + - Unhandled JsonDataException when a room is empty. + +### Other Changes: + - Update ThreeTenBP to 1.4.4 + - Update OkHttp to 4.8.0 + - Update Moshi to 1.9.3 + - Update Coroutines to 1.3.8 + 1.1.0 ----- diff --git a/groups/src/main/kotlin/inkapplications/shade/groups/ShadeGroupsModule.kt b/groups/src/main/kotlin/inkapplications/shade/groups/ShadeGroupsModule.kt index 4df984c2..7360bcdb 100644 --- a/groups/src/main/kotlin/inkapplications/shade/groups/ShadeGroupsModule.kt +++ b/groups/src/main/kotlin/inkapplications/shade/groups/ShadeGroupsModule.kt @@ -3,6 +3,7 @@ package inkapplications.shade.groups import com.squareup.moshi.Moshi import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory import inkapplications.shade.auth.TokenStorage +import inkapplications.shade.lights.ShadeLightsModule import inkapplications.shade.serialization.BrightnessTransformer import inkapplications.shade.serialization.ColorTemperatureTransformer import inkapplications.shade.serialization.CoordinatesListTransformer @@ -16,7 +17,9 @@ import shade.http.RateLimitInterceptor /** * Constructs Groups services. */ -class ShadeGroupsModule { +class ShadeGroupsModule( + val lightsModule: ShadeLightsModule = ShadeLightsModule() +) { /** * Create new instance of the Groups services. * @@ -47,6 +50,9 @@ class ShadeGroupsModule { .withSubtype(MutableGroupAttributes.Entertainment::class.java, "Entertainment") .withSubtype(MutableGroupAttributes.Zone::class.java, "Zone") ) + .apply { + lightsModule.transformers().forEach { add(it) } + } .add(ColorTemperatureTransformer) .add(CoordinatesListTransformer) .add(BrightnessTransformer) diff --git a/lights/src/main/kotlin/inkapplications/shade/lights/HueLightStateTransformer.kt b/lights/src/main/kotlin/inkapplications/shade/lights/HueLightStateTransformer.kt new file mode 100644 index 00000000..9abe8875 --- /dev/null +++ b/lights/src/main/kotlin/inkapplications/shade/lights/HueLightStateTransformer.kt @@ -0,0 +1,40 @@ +package inkapplications.shade.lights + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import inkapplications.shade.constructs.percent + +/** + * Convert internal hue representation to public object. + */ +internal object HueLightStateTransformer { + @FromJson + fun fromHue(state: HueLightState) = LightState( + on = state.on, + brightness = state.brightness ?: state.on.let { if (it) 100.percent else 0.percent }, + hue = state.hue, + saturation = state.saturation, + effect = state.effect, + cieColorCoordinates = state.cieColorCoordinates, + colorTemperature = state.colorTemperature, + alert = state.alert, + colorMode = state.colorMode, + mode = state.mode, + reachable = state.reachable + ) + + @ToJson + fun toHue(state: LightState) = HueLightState( + on = state.on, + brightness = state.brightness, + hue = state.hue, + saturation = state.saturation, + effect = state.effect, + cieColorCoordinates = state.cieColorCoordinates, + colorTemperature = state.colorTemperature, + alert = state.alert, + colorMode = state.colorMode, + mode = state.mode, + reachable = state.reachable + ) +} diff --git a/lights/src/main/kotlin/inkapplications/shade/lights/HueLightsApi.kt b/lights/src/main/kotlin/inkapplications/shade/lights/HueLightsApi.kt index 58845c3a..f86578b0 100644 --- a/lights/src/main/kotlin/inkapplications/shade/lights/HueLightsApi.kt +++ b/lights/src/main/kotlin/inkapplications/shade/lights/HueLightsApi.kt @@ -1,7 +1,12 @@ package inkapplications.shade.lights -import com.squareup.moshi.* +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass import inkapplications.shade.constructs.* +import inkapplications.shade.lights.AlertState.* +import inkapplications.shade.lights.ColorMode.* +import inkapplications.shade.lights.LightEffect.COLOR_LOOP +import inkapplications.shade.lights.LightEffect.NONE import org.threeten.bp.Duration import org.threeten.bp.Instant import retrofit2.http.* @@ -286,6 +291,24 @@ data class UpdateState( @Json(name="lastinstall") val lastInstall: Instant ) +/** + * Internal representation of the [LightState] class for json transformation. + */ +@JsonClass(generateAdapter = true) +internal data class HueLightState( + val on: Boolean, + @Json(name="bri") val brightness: Percentage?, + val hue: Int?, + @Json(name="sat") val saturation: Percentage?, + val effect: LightEffect?, + @Json(name="xy") val cieColorCoordinates: Coordinates?, + @Json(name="ct") val colorTemperature: ColorTemperature?, + val alert: AlertState?, + @Json(name="colormode") val colorMode: ColorMode?, + val mode: String?, + val reachable: Boolean? +) + /** * State of a light. * @@ -323,7 +346,6 @@ data class UpdateState( * @property mode Hue's Docs say nothing about this one. * @property reachable Indicates if a light can be reached by the bridge. */ -@JsonClass(generateAdapter = true) data class LightState( val on: Boolean, @Json(name="bri") val brightness: Percentage, diff --git a/lights/src/main/kotlin/inkapplications/shade/lights/ShadeLightsModule.kt b/lights/src/main/kotlin/inkapplications/shade/lights/ShadeLightsModule.kt index cbc265e4..cc091816 100644 --- a/lights/src/main/kotlin/inkapplications/shade/lights/ShadeLightsModule.kt +++ b/lights/src/main/kotlin/inkapplications/shade/lights/ShadeLightsModule.kt @@ -14,6 +14,16 @@ import shade.http.RateLimitInterceptor * Constructs lights services. */ class ShadeLightsModule { + fun transformers(): Set = setOf( + CoordinatesListTransformer, + InstantTransformer, + ColorTemperatureTransformer, + TemperatureRangeTransformer, + BrightnessTransformer, + DurationTransformer, + HueLightStateTransformer + ) + /** * Create a new instance of the lighting interface. * @@ -26,13 +36,8 @@ class ShadeLightsModule { .addInterceptor(RateLimitInterceptor) .build() val moshi = Moshi.Builder() - .add(CoordinatesListTransformer) - .add(InstantTransformer) .add(ScanAdapter) - .add(ColorTemperatureTransformer) - .add(TemperatureRangeTransformer) - .add(BrightnessTransformer) - .add(DurationTransformer) + .apply { transformers().forEach { add(it) } } .build() val retrofit = Retrofit.Builder() .client(apiClient)