Skip to content

Commit

Permalink
Handle null brightness on light states.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ReneeVandervelde committed Jul 19, 2020
1 parent 402e566 commit 732d7df
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 9 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
*
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
)
}
Original file line number Diff line number Diff line change
@@ -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.*
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ import shade.http.RateLimitInterceptor
* Constructs lights services.
*/
class ShadeLightsModule {
fun transformers(): Set<Any> = setOf(
CoordinatesListTransformer,
InstantTransformer,
ColorTemperatureTransformer,
TemperatureRangeTransformer,
BrightnessTransformer,
DurationTransformer,
HueLightStateTransformer
)

/**
* Create a new instance of the lighting interface.
*
Expand All @@ -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)
Expand Down

0 comments on commit 732d7df

Please sign in to comment.