add support for setting temperature, start apply command, refactor
This commit is contained in:
		
							parent
							
								
									6451ede58a
								
							
						
					
					
						commit
						ddd7fb7ed6
					
				
					 6 changed files with 94 additions and 16 deletions
				
			
		| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
package fi.schro.data
 | 
			
		||||
 | 
			
		||||
import fi.schro.util.FileUtil
 | 
			
		||||
import kotlinx.serialization.decodeFromString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import platform.posix.fopen
 | 
			
		||||
 | 
			
		||||
interface ConfigurationRepository {
 | 
			
		||||
    suspend fun applyConfiguration(configurationFilePath: String, lightAddress: String, port: Int? = null)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ConfigurationRepositoryImpl(
 | 
			
		||||
    private val lightRepository: LightRepository
 | 
			
		||||
): ConfigurationRepository {
 | 
			
		||||
    override suspend fun applyConfiguration(configurationFilePath: String, lightAddress: String, port: Int?) {
 | 
			
		||||
        val configString = FileUtil.readAllText(configurationFilePath)
 | 
			
		||||
        TODO("Not yet implemented")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private suspend fun applyLightStatus(lightAddress: String, port: Int?, status: LightStatus){
 | 
			
		||||
        val currentStatus = lightRepository.getLightStatus(lightAddress)
 | 
			
		||||
        currentStatus.getNecessaryChanges(status)?.let { statusUpdate ->
 | 
			
		||||
            lightRepository.setLightStatus(lightAddress, port, statusUpdate)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
package fi.schro.data
 | 
			
		||||
 | 
			
		||||
import fi.schro.ui.LightPowerState
 | 
			
		||||
import fi.schro.ui.LightPowerStatus
 | 
			
		||||
import io.ktor.client.*
 | 
			
		||||
import io.ktor.client.request.*
 | 
			
		||||
import io.ktor.client.statement.*
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +8,6 @@ import io.ktor.http.*
 | 
			
		|||
import io.ktor.utils.io.core.*
 | 
			
		||||
import kotlinx.serialization.SerialName
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
import platform.posix.stat
 | 
			
		||||
import kotlin.math.roundToInt
 | 
			
		||||
 | 
			
		||||
class ElgatoLightRepository(private val httpClient: HttpClient): LightRepository {
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +72,7 @@ data class ElgatoLight(
 | 
			
		|||
){
 | 
			
		||||
    fun toLightStatus(): LightStatus {
 | 
			
		||||
        return LightStatus(
 | 
			
		||||
            powerState = on?.let { LightPowerState.fromInt(it) },
 | 
			
		||||
            powerStatus = on?.let { LightPowerStatus.fromInt(it) },
 | 
			
		||||
            brightness = brightness,
 | 
			
		||||
            temperature = temperature?.let { convertElgatoTemperatureToKelvin(it) }
 | 
			
		||||
            )
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +81,7 @@ data class ElgatoLight(
 | 
			
		|||
    companion object {
 | 
			
		||||
        fun fromLightStatus(status: LightStatus): ElgatoLight {
 | 
			
		||||
            return ElgatoLight(
 | 
			
		||||
                on = status.powerState?.intValue,
 | 
			
		||||
                on = status.powerStatus?.intValue,
 | 
			
		||||
                brightness = status.brightness,
 | 
			
		||||
                temperature = status.temperature?.let { convertKelvinToElgatoTemperature(it) }
 | 
			
		||||
            )
 | 
			
		||||
| 
						 | 
				
			
			@ -90,9 +89,10 @@ data class ElgatoLight(
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//TODO: these calculations seem weird, maybe they could be improved
 | 
			
		||||
private fun convertKelvinToElgatoTemperature(kelvinTemperature: Int): Int {
 | 
			
		||||
    //TODO: implement real conversion
 | 
			
		||||
    return 319
 | 
			
		||||
    //based on: https://github.com/justinforlenza/keylight-control/blob/main/src/keylight.js
 | 
			
		||||
    return (((kelvinTemperature - 1993300/201f) * 201f)/-4100f).roundToInt()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private fun convertElgatoTemperatureToKelvin(elgatoTemperature: Int): Int {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,22 +1,37 @@
 | 
			
		|||
package fi.schro.data
 | 
			
		||||
 | 
			
		||||
import fi.schro.ui.LightPowerState
 | 
			
		||||
import fi.schro.ui.LightPowerStatus
 | 
			
		||||
import kotlinx.serialization.SerialName
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
 | 
			
		||||
interface LightRepository {
 | 
			
		||||
    suspend fun setLightStatus(lightAddress: String, port: Int? = null, status: LightStatus)
 | 
			
		||||
    suspend fun getLightStatus(lightAddress: String, port: Int? = null): LightStatus
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class LightStatus(
 | 
			
		||||
    val powerState: LightPowerState?,
 | 
			
		||||
    val brightness: Int?,
 | 
			
		||||
    val temperature: Int?
 | 
			
		||||
    @SerialName("power") val powerStatus: LightPowerStatus?,
 | 
			
		||||
    @SerialName("brightness") val brightness: Int?,
 | 
			
		||||
    @SerialName("temperature") val temperature: Int?
 | 
			
		||||
){
 | 
			
		||||
    override fun toString(): String {
 | 
			
		||||
        val stringList = mutableListOf<String>()
 | 
			
		||||
        powerState?.let { stringList.add("status: ${powerState.stringValue}") }
 | 
			
		||||
        powerStatus?.let { stringList.add("power: ${powerStatus.stringValue}") }
 | 
			
		||||
        brightness?.let { stringList.add("brightness: $brightness") }
 | 
			
		||||
        temperature?.let { stringList.add("temperature: $temperature") }
 | 
			
		||||
        return stringList.joinToString(separator = "\n")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getNecessaryChanges(otherStatus: LightStatus): LightStatus? {
 | 
			
		||||
        val statusUpdates = LightStatus(
 | 
			
		||||
            powerStatus = if(powerStatus != otherStatus.powerStatus) otherStatus.powerStatus else null,
 | 
			
		||||
            brightness = if(brightness != otherStatus.brightness) otherStatus.brightness else null,
 | 
			
		||||
            temperature = if(temperature != otherStatus.temperature) otherStatus.temperature else null
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return if(statusUpdates.powerStatus != null || statusUpdates.brightness != null || statusUpdates.temperature != null){
 | 
			
		||||
            statusUpdates
 | 
			
		||||
        } else null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
package fi.schro.di
 | 
			
		||||
 | 
			
		||||
import fi.schro.data.ConfigurationRepository
 | 
			
		||||
import fi.schro.data.ConfigurationRepositoryImpl
 | 
			
		||||
import fi.schro.data.ElgatoLightRepository
 | 
			
		||||
import fi.schro.data.LightRepository
 | 
			
		||||
import fi.schro.ui.ApplyCommand
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +20,7 @@ val commandModule = module {
 | 
			
		|||
 | 
			
		||||
val dataModule = module {
 | 
			
		||||
    single<LightRepository> { ElgatoLightRepository(get()) }
 | 
			
		||||
    single<ConfigurationRepository> { ConfigurationRepositoryImpl(get()) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val networkModule = module {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ import org.koin.core.component.inject
 | 
			
		|||
const val ARG_TARGET_LAMP = "TARGET_LAMP"
 | 
			
		||||
const val ARG_CONFIGURATION_FILE = "CONFIGURATION_FILE"
 | 
			
		||||
 | 
			
		||||
class HappyCatCommand: CliktCommand(), KoinComponent {
 | 
			
		||||
class HappyCatCommand: CliktCommand(name = "hc", help = "A commandline utility to control your elgato keylight"), KoinComponent {
 | 
			
		||||
    private val applyCommand: ApplyCommand by inject()
 | 
			
		||||
    private val getCommand: GetCommand by inject()
 | 
			
		||||
    private val setCommand: SetCommand by inject()
 | 
			
		||||
| 
						 | 
				
			
			@ -48,12 +48,12 @@ class SetCommand(
 | 
			
		|||
            it in 1000..10000
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private val powerState: LightPowerState? by option("-p", "--powerstate", help = "The state to be set").enum<LightPowerState>()
 | 
			
		||||
    private val powerStatus: LightPowerStatus? by option("-p", "--power", help = "The power status to be set").enum<LightPowerStatus>()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    override fun run() {
 | 
			
		||||
        val status = LightStatus(
 | 
			
		||||
            powerState = powerState,
 | 
			
		||||
            powerStatus = powerStatus,
 | 
			
		||||
            brightness = brightness,
 | 
			
		||||
            temperature = temperature
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -86,12 +86,12 @@ class ApplyCommand: CliktCommand(name = "apply", help = "Applies the given confi
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum class LightPowerState(val stringValue: String, val intValue: Int) {
 | 
			
		||||
enum class LightPowerStatus(val stringValue: String, val intValue: Int) {
 | 
			
		||||
    ON("ON", 1),
 | 
			
		||||
    OFF("OFF", 0);
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun fromInt(intValue: Int): LightPowerState? {
 | 
			
		||||
        fun fromInt(intValue: Int): LightPowerStatus? {
 | 
			
		||||
            return values().firstOrNull { it.intValue == intValue }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								src/nativeMain/kotlin/fi/schro/util/FileUtil.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/nativeMain/kotlin/fi/schro/util/FileUtil.kt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
package fi.schro.util
 | 
			
		||||
 | 
			
		||||
import kotlinx.cinterop.ByteVar
 | 
			
		||||
import kotlinx.cinterop.allocArray
 | 
			
		||||
import kotlinx.cinterop.memScoped
 | 
			
		||||
import kotlinx.cinterop.toKString
 | 
			
		||||
import platform.posix.fclose
 | 
			
		||||
import platform.posix.fgets
 | 
			
		||||
import platform.posix.fopen
 | 
			
		||||
 | 
			
		||||
object FileUtil {
 | 
			
		||||
    fun readAllText(filePath: String): String {
 | 
			
		||||
        val returnBuffer = StringBuilder()
 | 
			
		||||
        val file = fopen(filePath, "r") ?:
 | 
			
		||||
        throw IllegalArgumentException("Cannot open input file $filePath")
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            memScoped {
 | 
			
		||||
                val readBufferLength = 64 * 1024
 | 
			
		||||
                val buffer = allocArray<ByteVar>(readBufferLength)
 | 
			
		||||
                var line = fgets(buffer, readBufferLength, file)?.toKString()
 | 
			
		||||
                while (line != null) {
 | 
			
		||||
                    returnBuffer.append(line)
 | 
			
		||||
                    line = fgets(buffer, readBufferLength, file)?.toKString()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } finally {
 | 
			
		||||
            fclose(file)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return returnBuffer.toString()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue