Skip to content

Commit

Permalink
list broken by groups to reduce message size and added to readme.
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaruch committed Nov 27, 2024
1 parent 207abdc commit 89ef8f5
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 42 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* `/get_open_sensors` - Lists all sensors that are currently open.

* System Commands:
* `/list` - Shows all available devices grouped by type with their aliases.
* `/cancel_alerts` - Cancels all alerts in HSM.
* `/update` - Updates all hubs for which Hub Information Drivers are exposed in the Maker API of `hubitat.local`.
* `/reboot [Hub Information Driver v3 instance name]` - Reboots a specified hub.
Expand Down
98 changes: 76 additions & 22 deletions src/main/kotlin/DeviceManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DeviceManager(deviceListJson: String) {
val format = Json { ignoreUnknownKeys = true }
devices = format.decodeFromString<List<Device>>(deviceListJson)
deviceCache.clear()
val result: Pair<Int,List<String>> = Pair(devices.size, initializeCache(devices))
val result: Pair<Int, List<String>> = Pair(devices.size, initializeCache(devices))
return result
}

Expand All @@ -46,39 +46,93 @@ class DeviceManager(deviceListJson: String) {
return devices.filterIsInstance(type)
}

fun list(): String {
fun list(): String {
val deviceToAliases = mutableMapOf<Device, MutableList<String>>()
var maxDeviceNameLength = 0
var maxAliasesLength = 0

// Group aliases by device and find maximum lengths
deviceCache.forEach { (alias, device) ->
deviceToAliases.getOrPut(device) { mutableListOf() }.add(alias)
maxDeviceNameLength = maxOf(maxDeviceNameLength, device.label.length)
maxAliasesLength = maxOf(maxAliasesLength, deviceToAliases[device]!!.joinToString(", ").length)
}

// Ensure column headers don't get cut off
maxDeviceNameLength = maxOf(maxDeviceNameLength, "Device".length)
maxAliasesLength = maxOf(maxAliasesLength, "Aliases".length)

// Build the table string
val tableBuilder = StringBuilder()
tableBuilder.appendLine("```")
tableBuilder.appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")
tableBuilder.appendLine("| ${"Device".padEnd(maxDeviceNameLength)} | ${"Aliases".padEnd(maxAliasesLength)} |")
tableBuilder.appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")

deviceToAliases.forEach { (device, aliases) ->
val aliasesString = aliases.joinToString(", ")
tableBuilder.appendLine(
"| ${device.label.padEnd(maxDeviceNameLength)} | ${
aliasesString.padEnd(
maxAliasesLength
)
} |"
)
}

tableBuilder.appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")

tableBuilder.appendLine("```")
return tableBuilder.toString()
}

fun listByType(): Map<String, String> {
// Group devices by their base type
val devicesByType = deviceCache.values.groupBy { device ->
when (device) {
is Device.Actuator -> "Actuators"
is Device.Button -> "Buttons"
is Device.Sensor -> "Sensors"
is Device.Shade -> "Shades"
is Device.Hub -> "Hubs"
}
}.toSortedMap()

return devicesByType.mapValues { (_, devices) ->
val deviceToAliases = mutableMapOf<Device, MutableList<String>>()
var maxDeviceNameLength = 0
var maxAliasesLength = 0

// Group aliases by device and find maximum lengths
// Group aliases by device and find maximum lengths for this type
deviceCache.forEach { (alias, device) ->
deviceToAliases.getOrPut(device) { mutableListOf() }.add(alias)
maxDeviceNameLength = maxOf(maxDeviceNameLength, device.label.length)
maxAliasesLength = maxOf(maxAliasesLength, deviceToAliases[device]!!.joinToString(", ").length)
if (devices.contains(device)) {
deviceToAliases.getOrPut(device) { mutableListOf() }.add(alias)
maxDeviceNameLength = maxOf(maxDeviceNameLength, device.label.length)
maxAliasesLength = maxOf(maxAliasesLength, deviceToAliases[device]!!.joinToString(", ").length)
}
}

// Ensure column headers don't get cut off
maxDeviceNameLength = maxOf(maxDeviceNameLength, "Device".length)
maxAliasesLength = maxOf(maxAliasesLength, "Aliases".length)

// Build the table string
val tableBuilder = StringBuilder()
tableBuilder.appendLine("```")
tableBuilder.appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")
tableBuilder.appendLine("| ${"Device".padEnd(maxDeviceNameLength)} | ${"Aliases".padEnd(maxAliasesLength)} |")
tableBuilder.appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")

deviceToAliases.forEach { (device, aliases) ->
val aliasesString = aliases.joinToString(", ")
tableBuilder.appendLine("| ${device.label.padEnd(maxDeviceNameLength)} | ${aliasesString.padEnd(maxAliasesLength)} |")
}
buildString {
appendLine("```")
appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")
appendLine("| ${"Device".padEnd(maxDeviceNameLength)} | ${"Aliases".padEnd(maxAliasesLength)} |")
appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")

tableBuilder.appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")
deviceToAliases.forEach { (device, aliases) ->
val aliasesString = aliases.joinToString(", ")
appendLine("| ${device.label.padEnd(maxDeviceNameLength)} | ${aliasesString.padEnd(maxAliasesLength)} |")
}

tableBuilder.appendLine("```")
return tableBuilder.toString()
appendLine("+" + "-".repeat(maxDeviceNameLength + 2) + "+" + "-".repeat(maxAliasesLength + 2) + "+")
appendLine("```")
}
}
}


override fun toString(): String {
return devices.size.toString()
Expand Down Expand Up @@ -114,8 +168,8 @@ class DeviceManager(deviceListJson: String) {
return warnings
}

private fun addToCache(key: String, device: Device):List<String> {
var warnings: MutableList<String> = ArrayList()
private fun addToCache(key: String, device: Device): List<String> {
val warnings: MutableList<String> = ArrayList()
if (deviceCache.containsKey(key)) {
val message = "WARNING Duplicate key found in cache: $key"
warnings.add(message)
Expand Down
31 changes: 11 additions & 20 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,25 +76,16 @@ fun main() {
)
}
command("list") {
bot.sendMessage(
chatId = ChatId.fromId(message.chat.id),
text = deviceManager.list(),
parseMode = MARKDOWN_V2
)
}
command("shutdown_restart") {
//find hubs with z-wave on and iterate on them

//var zWaveHubs = deviceManager.findZWaveEnabledHubs()
//zWaveHubs.foreach{
// runDeviceCommand(it, "shutdown")
// bot.sendMessage(chatId = ChatId.fromId(message.chat.id), text = "Shutting down, please wait for graceful shutdown.")
// TimeUnit.MINUTES.sleep(1)
// bot.sendMessage(chatId = ChatId.fromId(message.chat.id), text = "Cutting power, please wait for radios reset.")
// TimeUnit.MINUTES.sleep(1)
// bot.sendMessage(chatId = ChatId.fromId(message.chat.id), text = "Restarting hub.")
//}
val chatId = ChatId.fromId(message.chat.id)
deviceManager.listByType().forEach { (type, table) ->
bot.sendMessage(
chatId = chatId,
text = "*$type*:\n$table",
parseMode = MARKDOWN_V2
)
}
}

command("get_open_sensors") {
val openSensors = deviceManager.findDevicesByType(Device.ContactSensor::class.java)
.mapNotNull { sensor ->
Expand Down Expand Up @@ -242,8 +233,8 @@ private suspend fun initHubs(): List<Device.Hub> {
}.body<String>()).jsonObject

val ip = (json["attributes"] as JsonArray).find {
it.jsonObject["name"]!!.jsonPrimitive.content.toString() == "localIP"
}!!.jsonObject["currentValue"]!!.jsonPrimitive.content.toString()
it.jsonObject["name"]!!.jsonPrimitive.content == "localIP"
}!!.jsonObject["currentValue"]!!.jsonPrimitive.content
hub.ip = ip
hub.managementToken = client.get("http://${ip}/hub/advanced/getManagementToken").body()
}
Expand Down

0 comments on commit 89ef8f5

Please sign in to comment.