From d98059bc2660a1d6725687389cd75b33c5d23135 Mon Sep 17 00:00:00 2001 From: Renee Vandervelde Date: Sun, 18 Jan 2026 11:24:10 -0600 Subject: [PATCH 1/2] Add Lightlevel module with get endpoints --- core/build.gradle.kts | 1 + .../inkapplications/shade/core/Shade.kt | 2 + lightlevel/build.gradle.kts | 28 ++++++++++++ .../shade/lightlevel/LightLevelControls.kt | 24 +++++++++++ .../shade/lightlevel/ShadeLightLevel.kt | 21 +++++++++ .../shade/lightlevel/ShadeLightLevelModule.kt | 14 ++++++ .../shade/lightlevel/structures/LightLevel.kt | 41 ++++++++++++++++++ .../lightlevel/structures/LightLevelReport.kt | 25 +++++++++++ .../lightlevel/structures/LightLevelValue.kt | 16 +++++++ settings.gradle.kts | 1 + .../shade/structures/FootCandles.kt | 34 +++++++++++++++ .../shade/structures/Illuminance.kt | 8 ++++ .../inkapplications/shade/structures/Lux.kt | 21 +++++++++ .../shade/structures/ScaledLux.kt | 43 +++++++++++++++++++ .../shade/structures/ScaledLuxSerializer.kt | 24 +++++++++++ 15 files changed, 303 insertions(+) create mode 100644 lightlevel/build.gradle.kts create mode 100644 lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt create mode 100644 lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt create mode 100644 lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevelModule.kt create mode 100644 lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevel.kt create mode 100644 lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelReport.kt create mode 100644 lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelValue.kt create mode 100644 structures/src/commonMain/kotlin/inkapplications/shade/structures/FootCandles.kt create mode 100644 structures/src/commonMain/kotlin/inkapplications/shade/structures/Illuminance.kt create mode 100644 structures/src/commonMain/kotlin/inkapplications/shade/structures/Lux.kt create mode 100644 structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLux.kt create mode 100644 structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLuxSerializer.kt diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 9abdfc51..ee6253b3 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -14,6 +14,7 @@ kotlin { api(projects.events) api(projects.groupedLights) api(projects.lights) + api(projects.lightlevel) api(projects.resources) api(projects.rooms) api(projects.scenes) diff --git a/core/src/commonMain/kotlin/inkapplications/shade/core/Shade.kt b/core/src/commonMain/kotlin/inkapplications/shade/core/Shade.kt index 60c22df9..12bec380 100644 --- a/core/src/commonMain/kotlin/inkapplications/shade/core/Shade.kt +++ b/core/src/commonMain/kotlin/inkapplications/shade/core/Shade.kt @@ -7,6 +7,7 @@ import inkapplications.shade.events.EventsModule import inkapplications.shade.groupedlights.ShadeGroupedLightsModule import inkapplications.shade.homekit.ShadeHomekitModule import inkapplications.shade.internals.InternalsModule +import inkapplications.shade.lightlevel.ShadeLightLevelModule import inkapplications.shade.lights.ShadeLightsModule import inkapplications.shade.resources.ShadeResourcesModule import inkapplications.shade.rooms.ShadeRoomsModule @@ -53,6 +54,7 @@ class Shade( ).bridgeAuth val devices = ShadeDevicesModule(internalsModule).devices val lights = ShadeLightsModule(internalsModule, eventsModule).lights + val lightLevels = ShadeLightLevelModule(internalsModule).lightLevels val rooms = ShadeRoomsModule(internalsModule).rooms val zones = ShadeZonesModule(internalsModule).zones val groupedLights = ShadeGroupedLightsModule(internalsModule, eventsModule).groupedLights diff --git a/lightlevel/build.gradle.kts b/lightlevel/build.gradle.kts new file mode 100644 index 00000000..04934cea --- /dev/null +++ b/lightlevel/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + id("library") + kotlin("plugin.serialization") + id("ink.publishing") +} + +kotlin { + sourceSets { + val commonMain by getting { + dependencies { + implementation(libs.serialization.json) + implementation(projects.internals) + implementation(projects.serialization) + api(projects.structures) + + api(libs.coroutines.core) + } + } + + val commonTest by getting { + dependencies { + implementation(libs.test.core) + implementation(libs.test.annotations) + } + } + } +} + diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt new file mode 100644 index 00000000..77647a47 --- /dev/null +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt @@ -0,0 +1,24 @@ +package inkapplications.shade.lightlevel + +import inkapplications.shade.lightlevel.structures.LightLevel +import inkapplications.shade.structures.ResourceId + +/** + * Actions to get light level sensor data from the hue system. + */ +interface LightLevelControls { + /** + * Get a list of light level sensors configured on the hue service. + * + * @return A list of all light level sensors configured on the bridge. + */ + suspend fun listLightLevels(): List + + /** + * Get the state of a single light level sensor. + * + * @param id The resource ID of the light level sensor to fetch data about. + * @return State and capability information about the light level sensor. + */ + suspend fun getLightLevel(id: ResourceId): LightLevel +} diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt new file mode 100644 index 00000000..6571d19a --- /dev/null +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt @@ -0,0 +1,21 @@ +package inkapplications.shade.lightlevel + +import inkapplications.shade.internals.HueHttpClient +import inkapplications.shade.internals.getData +import inkapplications.shade.lightlevel.structures.LightLevel +import inkapplications.shade.structures.ResourceId + +/** + * Implements light level sensor controls via the hue client. + */ +internal class ShadeLightLevel( + private val hueHttpClient: HueHttpClient, +): LightLevelControls { + override suspend fun listLightLevels(): List { + return hueHttpClient.getData("resource", "light_level") + } + + override suspend fun getLightLevel(id: ResourceId): LightLevel { + return hueHttpClient.getData>("resource", "light_level", id.value).single() + } +} diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevelModule.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevelModule.kt new file mode 100644 index 00000000..a4ceb8d4 --- /dev/null +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevelModule.kt @@ -0,0 +1,14 @@ +package inkapplications.shade.lightlevel + +import inkapplications.shade.internals.InternalsModule + +/** + * Provides access to light level sensor services. + * + * These are offered by devices with light level sensing capabilities. + */ +class ShadeLightLevelModule( + internalsModule: InternalsModule, +) { + val lightLevels: LightLevelControls = ShadeLightLevel(internalsModule.hueHttpClient) +} diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevel.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevel.kt new file mode 100644 index 00000000..5175cc25 --- /dev/null +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevel.kt @@ -0,0 +1,41 @@ +package inkapplications.shade.lightlevel.structures + +import inkapplications.shade.structures.ResourceId +import inkapplications.shade.structures.ResourceReference +import inkapplications.shade.structures.ResourceType +import kotlinx.serialization.Serializable + +/** + * State and capabilities of a light level sensor resource. + */ +@Serializable +data class LightLevel( + /** + * Unique identifier representing a specific light level sensor instance. + */ + val id: ResourceId, + + /** + * Owner of the service. + * + * In case the owner service is deleted, the service also gets deleted. + */ + val owner: ResourceReference, + + /** + * Whether the sensor is activated. + * + * true when sensor is activated, false when deactivated. + */ + val enabled: Boolean, + + /** + * Light level sensor data. + */ + val light: LightLevelValue, + + /** + * Type of the supported resource. + */ + val type: ResourceType = ResourceType.LightLevel, +) diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelReport.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelReport.kt new file mode 100644 index 00000000..45cb43c0 --- /dev/null +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelReport.kt @@ -0,0 +1,25 @@ +package inkapplications.shade.lightlevel.structures + +import inkapplications.shade.structures.Illuminance +import inkapplications.shade.structures.ScaledLuxSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlin.time.Instant + +/** + * Report containing light level sensor data. + */ +@Serializable +data class LightLevelReport( + /** + * Last time the value of this property was changed. + */ + val changed: Instant, + + /** + * Light level measured by sensor. + */ + @SerialName("light_level") + @Serializable(with = ScaledLuxSerializer::class) + val lightLevel: Illuminance, +) diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelValue.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelValue.kt new file mode 100644 index 00000000..5da9f346 --- /dev/null +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/structures/LightLevelValue.kt @@ -0,0 +1,16 @@ +package inkapplications.shade.lightlevel.structures + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Light level sensor data. + */ +@Serializable +data class LightLevelValue( + /** + * Detailed light level report with timestamp. + */ + @SerialName("light_level_report") + val lightLevelReport: LightLevelReport? = null, +) diff --git a/settings.gradle.kts b/settings.gradle.kts index a32864c9..69e8bab2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,7 @@ include("events") include("grouped-lights") include("homekit") include("internals") +include("lightlevel") include("lights") include("resources") include("rooms") diff --git a/structures/src/commonMain/kotlin/inkapplications/shade/structures/FootCandles.kt b/structures/src/commonMain/kotlin/inkapplications/shade/structures/FootCandles.kt new file mode 100644 index 00000000..a9cac355 --- /dev/null +++ b/structures/src/commonMain/kotlin/inkapplications/shade/structures/FootCandles.kt @@ -0,0 +1,34 @@ +package inkapplications.shade.structures + +import inkapplications.spondee.structure.Dimension +import inkapplications.spondee.structure.div +import inkapplications.spondee.structure.format +import kotlin.jvm.JvmInline + +private const val LUX_PER_FOOTCANDLE = 10.7639 + +/** + * Us customary unit of illuminance. + */ +@JvmInline +value class FootCandles(override val value: Number): Illuminance, Dimension { + override fun toLux(): Lux = value.toDouble().times(LUX_PER_FOOTCANDLE).lux + override fun withValue(value: Number): FootCandles = FootCandles(value) + override val symbol: String get() = "fc" + override fun toString(): String = format() +} + +/** + * Express this number as a unit in foot-candles + */ +val Number.footCandles get() = FootCandles(this) + +/** + * Convert this illuminance to foot-candles. + */ +fun Illuminance.toFootCandle(): FootCandles = toLux().div(LUX_PER_FOOTCANDLE).value.footCandles + +/** + * Convenience reference for a single foot-candle. + */ +val FootCandle = 1.footCandles diff --git a/structures/src/commonMain/kotlin/inkapplications/shade/structures/Illuminance.kt b/structures/src/commonMain/kotlin/inkapplications/shade/structures/Illuminance.kt new file mode 100644 index 00000000..a6d73abc --- /dev/null +++ b/structures/src/commonMain/kotlin/inkapplications/shade/structures/Illuminance.kt @@ -0,0 +1,8 @@ +package inkapplications.shade.structures + +/** + * Measurement of light intensity. + */ +interface Illuminance { + fun toLux(): Lux +} diff --git a/structures/src/commonMain/kotlin/inkapplications/shade/structures/Lux.kt b/structures/src/commonMain/kotlin/inkapplications/shade/structures/Lux.kt new file mode 100644 index 00000000..9bbf121e --- /dev/null +++ b/structures/src/commonMain/kotlin/inkapplications/shade/structures/Lux.kt @@ -0,0 +1,21 @@ +package inkapplications.shade.structures + +import inkapplications.spondee.structure.Dimension +import inkapplications.spondee.structure.format +import kotlin.jvm.JvmInline + +/** + * SI unit of illuminance. + */ +@JvmInline +value class Lux(override val value: Number): Illuminance, Dimension { + override fun toLux(): Lux = this + override fun withValue(value: Number): Lux = Lux(value) + override val symbol: String get() = "lx" + override fun toString(): String = format() +} + +/** + * Express this number as an illuminance unit in Lux. + */ +val Number.lux get() = Lux(this) diff --git a/structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLux.kt b/structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLux.kt new file mode 100644 index 00000000..5f34bc79 --- /dev/null +++ b/structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLux.kt @@ -0,0 +1,43 @@ +package inkapplications.shade.structures + +import inkapplications.spondee.structure.Dimension +import inkapplications.spondee.structure.format +import inkapplications.spondee.structure.toDouble +import kotlin.jvm.JvmInline +import kotlin.math.log10 +import kotlin.math.pow + +private const val SCALE_FACTOR = 10000.0 +private const val OFFSET = 1.0 + +/** + * Hue's custom logarithmic illuminance unit. + * Light level in 10000*log10(lux) + 1. + * + * Logarithmic scale used because the human eye adjusts to light levels + * and small changes at low lux levels are more noticeable than at high + * lux levels. This allows use of linear scale configuration sliders. + */ +@JvmInline +value class ScaledLux(override val value: Number) : Illuminance, Dimension { + override fun toLux(): Lux { + val logLux = (value.toDouble() - OFFSET) / SCALE_FACTOR + return 10.0.pow(logLux).lux + } + override fun withValue(value: Number): ScaledLux = ScaledLux(value) + override val symbol: String get() = "scaled lx" + override fun toString(): String = format() +} + +/** + * Express this number as a Hue LogLux unit. + */ +val Number.scaledLux get() = ScaledLux(this) + +/** + * Convert this illuminance to Hue LogLux. + */ +fun Illuminance.toScaledLux(): ScaledLux { + return toLux().toDouble().let(::log10) + .times(SCALE_FACTOR).plus(OFFSET).scaledLux +} diff --git a/structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLuxSerializer.kt b/structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLuxSerializer.kt new file mode 100644 index 00000000..daadb7ab --- /dev/null +++ b/structures/src/commonMain/kotlin/inkapplications/shade/structures/ScaledLuxSerializer.kt @@ -0,0 +1,24 @@ +package inkapplications.shade.structures + +import inkapplications.spondee.structure.roundToInt +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +/** + * Serializes an illuminance value in hue's scaled logarithmic lux units. + */ +object ScaledLuxSerializer: KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Illuminance", PrimitiveKind.INT) + + override fun serialize(encoder: Encoder, value: Illuminance) { + encoder.encodeInt(value.toScaledLux().roundToInt()) + } + + override fun deserialize(decoder: Decoder): ScaledLux { + return decoder.decodeInt().scaledLux + } +} From 16ecc40acd4ca0dfbfe786a6166aa74b65815b8a Mon Sep 17 00:00:00 2001 From: Renee Vandervelde Date: Sun, 18 Jan 2026 11:43:24 -0600 Subject: [PATCH 2/2] Add update endpoint for light-levels --- core/api/core.api | 1 + lightlevel/api/lightlevel.api | 134 ++++++++++++++++++ .../shade/lightlevel/LightLevelControls.kt | 11 ++ .../shade/lightlevel/ShadeLightLevel.kt | 15 ++ .../parameters/LightLevelUpdateParameters.kt | 17 +++ structures/api/structures.api | 91 ++++++++++++ 6 files changed, 269 insertions(+) create mode 100644 lightlevel/api/lightlevel.api create mode 100644 lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters.kt diff --git a/core/api/core.api b/core/api/core.api index acb47971..4decccbc 100644 --- a/core/api/core.api +++ b/core/api/core.api @@ -12,6 +12,7 @@ public final class inkapplications/shade/core/Shade { public final fun getDevices ()Linkapplications/shade/devices/DeviceControls; public final fun getGroupedLights ()Linkapplications/shade/groupedlights/GroupedLightControls; public final fun getHomekit ()Linkapplications/shade/homekit/HomekitControls; + public final fun getLightLevels ()Linkapplications/shade/lightlevel/LightLevelControls; public final fun getLights ()Linkapplications/shade/lights/LightControls; public final fun getOnlineDiscovery ()Linkapplications/shade/discover/BridgeDiscovery; public final fun getResources ()Linkapplications/shade/resources/ResourceControls; diff --git a/lightlevel/api/lightlevel.api b/lightlevel/api/lightlevel.api new file mode 100644 index 00000000..9880397b --- /dev/null +++ b/lightlevel/api/lightlevel.api @@ -0,0 +1,134 @@ +public abstract interface class inkapplications/shade/lightlevel/LightLevelControls { + public abstract fun getLightLevel-klA6Vuc (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun listLightLevels (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public abstract fun updateLightLevel-bKh5c1I (Ljava/lang/String;Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; +} + +public final class inkapplications/shade/lightlevel/ShadeLightLevelModule { + public fun (Linkapplications/shade/internals/InternalsModule;)V + public final fun getLightLevels ()Linkapplications/shade/lightlevel/LightLevelControls; +} + +public final class inkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters { + public static final field Companion Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters$Companion; + public fun ()V + public fun (Ljava/lang/Boolean;)V + public synthetic fun (Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/Boolean; + public final fun copy (Ljava/lang/Boolean;)Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters; + public static synthetic fun copy$default (Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters;Ljava/lang/Boolean;ILjava/lang/Object;)Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters; + public fun equals (Ljava/lang/Object;)Z + public final fun getEnabled ()Ljava/lang/Boolean; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final synthetic class inkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Linkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class inkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class inkapplications/shade/lightlevel/structures/LightLevel { + public static final field Companion Linkapplications/shade/lightlevel/structures/LightLevel$Companion; + public synthetic fun (Ljava/lang/String;Linkapplications/shade/structures/ResourceReference;ZLinkapplications/shade/lightlevel/structures/LightLevelValue;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Linkapplications/shade/structures/ResourceReference;ZLinkapplications/shade/lightlevel/structures/LightLevelValue;Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1-XbiYvy0 ()Ljava/lang/String; + public final fun component2 ()Linkapplications/shade/structures/ResourceReference; + public final fun component3 ()Z + public final fun component4 ()Linkapplications/shade/lightlevel/structures/LightLevelValue; + public final fun component5-1y3a6N0 ()Ljava/lang/String; + public final fun copy-qm0Ps9A (Ljava/lang/String;Linkapplications/shade/structures/ResourceReference;ZLinkapplications/shade/lightlevel/structures/LightLevelValue;Ljava/lang/String;)Linkapplications/shade/lightlevel/structures/LightLevel; + public static synthetic fun copy-qm0Ps9A$default (Linkapplications/shade/lightlevel/structures/LightLevel;Ljava/lang/String;Linkapplications/shade/structures/ResourceReference;ZLinkapplications/shade/lightlevel/structures/LightLevelValue;Ljava/lang/String;ILjava/lang/Object;)Linkapplications/shade/lightlevel/structures/LightLevel; + public fun equals (Ljava/lang/Object;)Z + public final fun getEnabled ()Z + public final fun getId-XbiYvy0 ()Ljava/lang/String; + public final fun getLight ()Linkapplications/shade/lightlevel/structures/LightLevelValue; + public final fun getOwner ()Linkapplications/shade/structures/ResourceReference; + public final fun getType-1y3a6N0 ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final synthetic class inkapplications/shade/lightlevel/structures/LightLevel$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Linkapplications/shade/lightlevel/structures/LightLevel$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Linkapplications/shade/lightlevel/structures/LightLevel; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Linkapplications/shade/lightlevel/structures/LightLevel;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class inkapplications/shade/lightlevel/structures/LightLevel$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class inkapplications/shade/lightlevel/structures/LightLevelReport { + public static final field Companion Linkapplications/shade/lightlevel/structures/LightLevelReport$Companion; + public fun (Lkotlin/time/Instant;Linkapplications/shade/structures/Illuminance;)V + public final fun component1 ()Lkotlin/time/Instant; + public final fun component2 ()Linkapplications/shade/structures/Illuminance; + public final fun copy (Lkotlin/time/Instant;Linkapplications/shade/structures/Illuminance;)Linkapplications/shade/lightlevel/structures/LightLevelReport; + public static synthetic fun copy$default (Linkapplications/shade/lightlevel/structures/LightLevelReport;Lkotlin/time/Instant;Linkapplications/shade/structures/Illuminance;ILjava/lang/Object;)Linkapplications/shade/lightlevel/structures/LightLevelReport; + public fun equals (Ljava/lang/Object;)Z + public final fun getChanged ()Lkotlin/time/Instant; + public final fun getLightLevel ()Linkapplications/shade/structures/Illuminance; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final synthetic class inkapplications/shade/lightlevel/structures/LightLevelReport$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Linkapplications/shade/lightlevel/structures/LightLevelReport$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Linkapplications/shade/lightlevel/structures/LightLevelReport; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Linkapplications/shade/lightlevel/structures/LightLevelReport;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class inkapplications/shade/lightlevel/structures/LightLevelReport$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class inkapplications/shade/lightlevel/structures/LightLevelValue { + public static final field Companion Linkapplications/shade/lightlevel/structures/LightLevelValue$Companion; + public fun ()V + public fun (Linkapplications/shade/lightlevel/structures/LightLevelReport;)V + public synthetic fun (Linkapplications/shade/lightlevel/structures/LightLevelReport;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Linkapplications/shade/lightlevel/structures/LightLevelReport; + public final fun copy (Linkapplications/shade/lightlevel/structures/LightLevelReport;)Linkapplications/shade/lightlevel/structures/LightLevelValue; + public static synthetic fun copy$default (Linkapplications/shade/lightlevel/structures/LightLevelValue;Linkapplications/shade/lightlevel/structures/LightLevelReport;ILjava/lang/Object;)Linkapplications/shade/lightlevel/structures/LightLevelValue; + public fun equals (Ljava/lang/Object;)Z + public final fun getLightLevelReport ()Linkapplications/shade/lightlevel/structures/LightLevelReport; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final synthetic class inkapplications/shade/lightlevel/structures/LightLevelValue$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Linkapplications/shade/lightlevel/structures/LightLevelValue$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Linkapplications/shade/lightlevel/structures/LightLevelValue; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Linkapplications/shade/lightlevel/structures/LightLevelValue;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class inkapplications/shade/lightlevel/structures/LightLevelValue$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt index 77647a47..68ff0f0a 100644 --- a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/LightLevelControls.kt @@ -1,7 +1,9 @@ package inkapplications.shade.lightlevel +import inkapplications.shade.lightlevel.parameters.LightLevelUpdateParameters import inkapplications.shade.lightlevel.structures.LightLevel import inkapplications.shade.structures.ResourceId +import inkapplications.shade.structures.ResourceReference /** * Actions to get light level sensor data from the hue system. @@ -21,4 +23,13 @@ interface LightLevelControls { * @return State and capability information about the light level sensor. */ suspend fun getLightLevel(id: ResourceId): LightLevel + + /** + * Update a light level sensor on the hue bridge. + * + * @param id The resource ID of the light level sensor to be updated. + * @param parameters Data about the light level sensor to be updated. + * @return A reference to the updated resource. + */ + suspend fun updateLightLevel(id: ResourceId, parameters: LightLevelUpdateParameters): ResourceReference } diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt index 6571d19a..d8cbd72e 100644 --- a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/ShadeLightLevel.kt @@ -2,8 +2,11 @@ package inkapplications.shade.lightlevel import inkapplications.shade.internals.HueHttpClient import inkapplications.shade.internals.getData +import inkapplications.shade.internals.putData +import inkapplications.shade.lightlevel.parameters.LightLevelUpdateParameters import inkapplications.shade.lightlevel.structures.LightLevel import inkapplications.shade.structures.ResourceId +import inkapplications.shade.structures.ResourceReference /** * Implements light level sensor controls via the hue client. @@ -18,4 +21,16 @@ internal class ShadeLightLevel( override suspend fun getLightLevel(id: ResourceId): LightLevel { return hueHttpClient.getData>("resource", "light_level", id.value).single() } + + override suspend fun updateLightLevel( + id: ResourceId, + parameters: LightLevelUpdateParameters + ): ResourceReference { + val response: List = hueHttpClient.putData( + body = parameters, + pathSegments = arrayOf("resource", "light_level", id.value), + ) + + return response.single() + } } diff --git a/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters.kt b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters.kt new file mode 100644 index 00000000..2a8c8772 --- /dev/null +++ b/lightlevel/src/commonMain/kotlin/inkapplications/shade/lightlevel/parameters/LightLevelUpdateParameters.kt @@ -0,0 +1,17 @@ +package inkapplications.shade.lightlevel.parameters + +import kotlinx.serialization.Serializable + +/** + * Parameters that can be specified when updating a light level sensor. + */ +@Serializable +data class LightLevelUpdateParameters( + /** + * Whether the sensor is activated. + * + * true when sensor is activated, false when deactivated. + */ + val enabled: Boolean? = null, +) + diff --git a/structures/api/structures.api b/structures/api/structures.api index d78375b4..b05a64f9 100644 --- a/structures/api/structures.api +++ b/structures/api/structures.api @@ -42,6 +42,33 @@ public final class inkapplications/shade/structures/AuthorizationTimeoutExceptio public static final field INSTANCE Linkapplications/shade/structures/AuthorizationTimeoutException; } +public final class inkapplications/shade/structures/FootCandles : inkapplications/shade/structures/Illuminance, inkapplications/spondee/structure/Dimension { + public static final synthetic fun box-impl (Ljava/lang/Number;)Linkapplications/shade/structures/FootCandles; + public static fun constructor-impl (Ljava/lang/Number;)Ljava/lang/Number; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/lang/Number;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/lang/Number;Ljava/lang/Number;)Z + public fun getSymbol ()Ljava/lang/String; + public static fun getSymbol-impl (Ljava/lang/Number;)Ljava/lang/String; + public fun getValue ()Ljava/lang/Number; + public fun hashCode ()I + public static fun hashCode-impl (Ljava/lang/Number;)I + public fun toLux-bPG8OSU ()Ljava/lang/Number; + public static fun toLux-bPG8OSU (Ljava/lang/Number;)Ljava/lang/Number; + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/lang/Number;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/lang/Number; + public synthetic fun withValue (Ljava/lang/Number;)Ljava/lang/Object; + public fun withValue-N83p2f4 (Ljava/lang/Number;)Ljava/lang/Number; + public static fun withValue-N83p2f4 (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number; +} + +public final class inkapplications/shade/structures/FootCandlesKt { + public static final fun getFootCandle ()Ljava/lang/Number; + public static final fun getFootCandles (Ljava/lang/Number;)Ljava/lang/Number; + public static final fun toFootCandle (Linkapplications/shade/structures/Illuminance;)Ljava/lang/Number; +} + public final class inkapplications/shade/structures/HostnameNotSetException : inkapplications/shade/structures/UserError { public static final field INSTANCE Linkapplications/shade/structures/HostnameNotSetException; } @@ -55,6 +82,10 @@ public abstract interface class inkapplications/shade/structures/HueConfiguratio public abstract fun setSecurityStrategy (Linkapplications/shade/structures/SecurityStrategy;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } +public abstract interface class inkapplications/shade/structures/Illuminance { + public abstract fun toLux-bPG8OSU ()Ljava/lang/Number; +} + public final class inkapplications/shade/structures/InMemoryConfigurationContainer : inkapplications/shade/structures/HueConfigurationContainer { public fun ()V public fun (Ljava/lang/String;Linkapplications/shade/structures/AuthToken;Linkapplications/shade/structures/SecurityStrategy;)V @@ -74,6 +105,31 @@ public final class inkapplications/shade/structures/InvalidConfigurationExceptio public fun (Ljava/lang/String;)V } +public final class inkapplications/shade/structures/Lux : inkapplications/shade/structures/Illuminance, inkapplications/spondee/structure/Dimension { + public static final synthetic fun box-impl (Ljava/lang/Number;)Linkapplications/shade/structures/Lux; + public static fun constructor-impl (Ljava/lang/Number;)Ljava/lang/Number; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/lang/Number;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/lang/Number;Ljava/lang/Number;)Z + public fun getSymbol ()Ljava/lang/String; + public static fun getSymbol-impl (Ljava/lang/Number;)Ljava/lang/String; + public fun getValue ()Ljava/lang/Number; + public fun hashCode ()I + public static fun hashCode-impl (Ljava/lang/Number;)I + public fun toLux-bPG8OSU ()Ljava/lang/Number; + public static fun toLux-bPG8OSU (Ljava/lang/Number;)Ljava/lang/Number; + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/lang/Number;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/lang/Number; + public synthetic fun withValue (Ljava/lang/Number;)Ljava/lang/Object; + public fun withValue-maF8XeE (Ljava/lang/Number;)Ljava/lang/Number; + public static fun withValue-maF8XeE (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number; +} + +public final class inkapplications/shade/structures/LuxKt { + public static final fun getLux (Ljava/lang/Number;)Ljava/lang/Number; +} + public final class inkapplications/shade/structures/NetworkException : inkapplications/shade/structures/ShadeException { public fun (Ljava/lang/String;Ljava/lang/Throwable;)V } @@ -261,6 +317,41 @@ public final class inkapplications/shade/structures/ResourceType$Companion { public final fun values ()[Linkapplications/shade/structures/ResourceType; } +public final class inkapplications/shade/structures/ScaledLux : inkapplications/shade/structures/Illuminance, inkapplications/spondee/structure/Dimension { + public static final synthetic fun box-impl (Ljava/lang/Number;)Linkapplications/shade/structures/ScaledLux; + public static fun constructor-impl (Ljava/lang/Number;)Ljava/lang/Number; + public fun equals (Ljava/lang/Object;)Z + public static fun equals-impl (Ljava/lang/Number;Ljava/lang/Object;)Z + public static final fun equals-impl0 (Ljava/lang/Number;Ljava/lang/Number;)Z + public fun getSymbol ()Ljava/lang/String; + public static fun getSymbol-impl (Ljava/lang/Number;)Ljava/lang/String; + public fun getValue ()Ljava/lang/Number; + public fun hashCode ()I + public static fun hashCode-impl (Ljava/lang/Number;)I + public fun toLux-bPG8OSU ()Ljava/lang/Number; + public static fun toLux-bPG8OSU (Ljava/lang/Number;)Ljava/lang/Number; + public fun toString ()Ljava/lang/String; + public static fun toString-impl (Ljava/lang/Number;)Ljava/lang/String; + public final synthetic fun unbox-impl ()Ljava/lang/Number; + public synthetic fun withValue (Ljava/lang/Number;)Ljava/lang/Object; + public fun withValue-V6cn6iE (Ljava/lang/Number;)Ljava/lang/Number; + public static fun withValue-V6cn6iE (Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number; +} + +public final class inkapplications/shade/structures/ScaledLuxKt { + public static final fun getScaledLux (Ljava/lang/Number;)Ljava/lang/Number; + public static final fun toScaledLux (Linkapplications/shade/structures/Illuminance;)Ljava/lang/Number; +} + +public final class inkapplications/shade/structures/ScaledLuxSerializer : kotlinx/serialization/KSerializer { + public static final field INSTANCE Linkapplications/shade/structures/ScaledLuxSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize-V6cn6iE (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Number; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Linkapplications/shade/structures/Illuminance;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V +} + public class inkapplications/shade/structures/SecurityStrategy { }