Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0a4bda6
initial changes for HA
mretallack Dec 7, 2025
95c20aa
inital version
mretallack Dec 7, 2025
588c679
fixes
mretallack Dec 7, 2025
7cd06f5
more fixes
mretallack Dec 7, 2025
5fe39f5
changes
mretallack Dec 7, 2025
53c02b3
Fixes for first working version
markretallack Dec 8, 2025
7459802
Added more tests
markretallack Dec 8, 2025
69d38bc
Added persion location
markretallack Dec 8, 2025
07c9e2a
Added docs
markretallack Dec 8, 2025
b0338a6
remove unwanted Files
markretallack Dec 8, 2025
0e13e58
Remove unwanted files
markretallack Dec 8, 2025
74c7322
Added import and export support
mretallack Jan 10, 2026
31b8cc0
Add Home Assistant help command with comprehensive usage examples
mretallack Jan 10, 2026
1a139dc
Merge remote-tracking branch 'upstream/master' into changes-for-ha
mretallack Feb 6, 2026
0b2a42a
Add requirements spec for Home Assistant media source control
mretallack Feb 6, 2026
6fa92c8
Add design document for Home Assistant media source control
mretallack Feb 6, 2026
a9cb98b
Update design with API research findings and callService extension
mretallack Feb 6, 2026
7e734fd
Add comprehensive unit and integration testing specifications
mretallack Feb 6, 2026
cd5a659
Add investigation findings: fuzzy matching, entity mapping, UI design
mretallack Feb 6, 2026
433d206
Add references to investigation documents in design.md
mretallack Feb 6, 2026
55e12a1
Resolve all remaining unknowns: threshold, generated class, ambiguous…
mretallack Feb 6, 2026
a0a9a4c
Add fuzzy matching algorithm tests - 20/20 tests pass with real data
mretallack Feb 6, 2026
6985ccd
Add implementation tasks document with 8 phases and 35 tasks
mretallack Feb 6, 2026
9de0af8
Add Home Assistant media player source selection feature
mretallack Feb 6, 2026
8283bd5
Fix UI text for select source success message
mretallack Feb 7, 2026
eac7536
Add number variation approach to HA media source spec
mretallack Feb 7, 2026
713d694
Implement number variation handling for HA media source selection
mretallack Feb 7, 2026
f39776f
Merge pull request #1 from mretallack/changes-for-ha-dev
mretallack Feb 8, 2026
6214813
Docs: Update Home Assistant skill description
mretallack Mar 1, 2026
b674f1d
Merge master into changes-for-ha
mretallack Mar 1, 2026
958b4cf
Fix: Update Home Assistant tests for new API
mretallack Mar 1, 2026
a69152c
Fix: Home Assistant tests now pass with TestSkillContext
mretallack Mar 1, 2026
9bd2ab8
Chore: Move .kiro directory to local-only
mretallack Mar 1, 2026
322d009
Docs: Move SETUP.md to docs/skills/home-assistant.md
mretallack Mar 1, 2026
ad2eaee
Docs: Remove reference to non-existent .amazonq file
mretallack Mar 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@
fastlane/report.xml
fastlane/README.md
fastlane_config.txt

# Kiro specs (local only)
.kiro/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Currently Dicio answers questions about:
- **media**: play, pause, previous, next song
- **translation**: translate from/to any language with **Lingva** - _How do I say Football in German?_
- **wake word control**: turn on/off the wakeword - _Stop listening_
- **home assistant**: query and control **Home Assistant** entities - _Turn living room light on_, _Turn kitchen radio to BBC Radio 2_
- Note: Media source selection with number homophones (e.g., "too" → "2") is currently English-only
- **notifications**: reads all notifications currently in the status bar - _What are my notifications?_
- **flashlight**: turn on/off the phone flashlight - _Turn on the flashlight_

Expand Down
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ dependencies {

// Used by skills
implementation(libs.exp4j)

// YAML processing
implementation("org.yaml:snakeyaml:2.0")

// Testing
testImplementation(libs.kotest.runner.junit5)
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/kotlin/org/stypox/dicio/eval/SkillHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import org.stypox.dicio.settings.datastore.UserSettingsModule
import org.stypox.dicio.skills.calculator.CalculatorInfo
import org.stypox.dicio.skills.current_time.CurrentTimeInfo
import org.stypox.dicio.skills.fallback.text.TextFallbackInfo
import org.stypox.dicio.skills.homeassistant.HomeAssistantInfo
import org.stypox.dicio.skills.listening.ListeningInfo
import org.stypox.dicio.skills.lyrics.LyricsInfo
import org.stypox.dicio.skills.media.MediaInfo
Expand Down Expand Up @@ -57,6 +58,7 @@ class SkillHandler @Inject constructor(
JokeInfo,
ListeningInfo(dataStore),
TranslationInfo,
HomeAssistantInfo,
NotifyInfo,
FlashlightInfo,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.stypox.dicio.skills.homeassistant

import org.json.JSONArray
import org.json.JSONObject
import org.stypox.dicio.util.ConnectionUtils
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL

object HomeAssistantApi {
@Throws(IOException::class)
suspend fun getAllStates(baseUrl: String, token: String): JSONArray {
val connection = URL("$baseUrl/api/states").openConnection() as HttpURLConnection
connection.setRequestProperty("Authorization", "Bearer $token")
connection.setRequestProperty("Content-Type", "application/json")

val scanner = java.util.Scanner(connection.inputStream)
val response = scanner.useDelimiter("\\A").next()
scanner.close()

return JSONArray(response)
}

@Throws(IOException::class)
suspend fun getEntityState(baseUrl: String, token: String, entityId: String): JSONObject {
val connection = URL("$baseUrl/api/states/$entityId").openConnection() as HttpURLConnection
connection.setRequestProperty("Authorization", "Bearer $token")
connection.setRequestProperty("Content-Type", "application/json")

val scanner = java.util.Scanner(connection.inputStream)
val response = scanner.useDelimiter("\\A").next()
scanner.close()

return JSONObject(response)
}

@Throws(IOException::class)
suspend fun callService(
baseUrl: String,
token: String,
domain: String,
service: String,
entityId: String,
extraParams: Map<String, String> = emptyMap()
): JSONArray {
val connection = URL("$baseUrl/api/services/$domain/$service").openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("Authorization", "Bearer $token")
connection.setRequestProperty("Content-Type", "application/json")
connection.doOutput = true

val body = JSONObject().put("entity_id", entityId)
extraParams.forEach { (key, value) -> body.put(key, value) }

connection.outputStream.write(body.toString().toByteArray())

val scanner = java.util.Scanner(connection.inputStream)
val response = scanner.useDelimiter("\\A").next()
scanner.close()

return JSONArray(response)
}
}
Loading