ChatGPT Wrote a Working Basic Hubitat App

Microsoft bought Github for a reason :slightly_smiling_face:

There's a whole lot of supervision/engineering that goes on to train these models.

Each generation has to pass a series of tests.

2 Likes

Just took ChatGPT for a test drive to create a virtual message device, added a few bells and whistles to it and like most AI's its gets it nearly right, so spent cycles correcting compilation/runtime errors and expanding the feature set and advising it on the fact that runInMills does exist. Here is a virtual driver that can display messages like on Sharptools for example and has some server side animations (flash, disappear and scroll in the banner). Not something I would recommend but does provide something of an example of what is possible with limited human coding. CursorAI (runs on Visual Code) might be a bit better as you can point it to more recent docs than what ChatGPT was trained on. I feel that computer and actually most other jobs are safe for now as it still needs this human check cycle for ambiguous/interpretive input.

metadata {
    definition(name: "Message Storage Virtual Device", namespace: "yourNamespace", author: "YourName") {
        capability "Actuator"
        capability "Refresh"
        capability "Sensor"
        capability "Configuration"

        attribute "message", "string"
        attribute "message2", "string"
        attribute "message3", "string"

        command "updateMessage", ["string"]
        command "updateMessage2", ["string"]
        command "updateMessage3", ["string"]
        command "clearMessage"
        command "setMessageStyle", ["string"]
    }
}

preferences {
    input name: "defaultMessage", type: "string", title: "Default Message", description: "Message to display initially", required: false, defaultValue: "Hello, World!"
    input name: "defaultMessage2", type: "string", title: "Default Message 2", description: "Second message to display initially", required: false, defaultValue: "Hello, Universe!"
    input name: "defaultMessage3", type: "string", title: "Default Message 3", description: "Third message to display initially", required: false, defaultValue: "Hello, Galaxy!"
    input name: "messageStyle", type: "enum", title: "Message Style", description: "Choose the message style", options: ["static", "disappear", "flash", "rotate", "banner"], defaultValue: "static"
    input name: "flashDisplayTime", type: "decimal", title: "Flash Display Time (seconds)", description: "Time the message is displayed during flash, minimum 1 second", required: false, defaultValue: 10
    input name: "flashDisappearTime", type: "decimal", title: "Flash Disappear Time (seconds)", description: "Time the message is hidden during flash, minimum 1 second", required: false, defaultValue: 2
    input name: "bannerWindowSize", type: "number", title: "Banner Display Window Size", description: "Number of characters to display in the sliding window", required: false, defaultValue: 20
}

def installed() {
    log.debug "Installed with settings: ${settings}"
    initialize()
}

def updated() {
    log.debug "Updated with settings: ${settings}"
    initialize()
}

def initialize() {
    log.debug "Initializing device"
    sendEvent(name: "message", value: settings.defaultMessage ?: " ", displayed: true)
    sendEvent(name: "message2", value: settings.defaultMessage2 ?: " ", displayed: true)
    sendEvent(name: "message3", value: settings.defaultMessage3 ?: " ", displayed: true)
    if (!settings.messageStyle) {
        setMessageStyle("static")
    } else {
        setMessageStyle(settings.messageStyle)
    }
}

def updateMessage(String newMessage) {
    log.debug "Updating message to: $newMessage"
    sendEvent(name: "message", value: newMessage, displayed: true)
}

def updateMessage2(String newMessage) {
    log.debug "Updating message2 to: $newMessage"
    sendEvent(name: "message2", value: newMessage, displayed: true)
}

def updateMessage3(String newMessage) {
    log.debug "Updating message3 to: $newMessage"
    sendEvent(name: "message3", value: newMessage, displayed: true)
}

def clearMessage() {
    log.debug "Clearing messages"
    sendEvent(name: "message", value: " ", displayed: true)
    sendEvent(name: "message2", value: " ", displayed: true)
    sendEvent(name: "message3", value: " ", displayed: true)
}

def setMessageStyle(String style) {
    log.debug "Setting message style to: $style"
    switch (style) {
        case "static":
            unschedule() // Stop any scheduled tasks
            break
        case "disappear":
            unschedule()
            runIn((settings.flashDisplayTime ?: 10).toBigDecimal().floatValue().toInteger(), "clearMessage")
            break
        case "flash":
            unschedule()
            flashMessage()
            break
        case "rotate":
            unschedule()
            rotateMessages([currentIndex: 0])
            break
        case "banner":
            unschedule()
            bannerMessage([offset: 0])
            break
    }
}

def flashMessage() {
    def currentMessage = device.currentValue("message") ?: settings.defaultMessage ?: " "
    def isCurrentlyEmpty = (currentMessage.trim() == "")
    def nextMessage = isCurrentlyEmpty ? (settings.defaultMessage ?: " ") : " "
    sendEvent(name: "message", value: nextMessage, displayed: true)
    def displayTime = Math.max((settings.flashDisplayTime ?: 10).toBigDecimal().floatValue(), 1.0)
    def disappearTime = Math.max((settings.flashDisappearTime ?: 2).toBigDecimal().floatValue(), 1.0)
    runInMillis(((isCurrentlyEmpty ? displayTime : disappearTime) * 1000).toInteger(), "flashMessage")
}

def rotateMessages(data) {
    def currentIndex = data.currentIndex ?: 0
    def messages = [
        settings.defaultMessage ?: " ",
        settings.defaultMessage2 ?: " ",
        settings.defaultMessage3 ?: " "
    ]
    def messageToDisplay = messages[currentIndex % messages.size()]
    sendEvent(name: "message", value: messageToDisplay, displayed: true)
    def disappearTime = Math.max((settings.flashDisplayTime ?: 10).toBigDecimal().floatValue(), 1.0)
    runInMillis((disappearTime * 1000).toInteger(), "rotateMessages", [data: [currentIndex: currentIndex + 1]])
}

def bannerMessage(data) {
    def offset = data.offset ?: 0
    def messages = [
        settings.defaultMessage ?: " ",
        settings.defaultMessage2 ?: " ",
        settings.defaultMessage3 ?: " "
    ]
    def combinedMessage = messages.join(" ").trim()
    def windowSize = settings.bannerWindowSize ?: 20

    log.debug "Banner message invoked. Offset: $offset, Combined Message: $combinedMessage"

    // Ensure combined message is long enough to scroll
    def paddedMessage = combinedMessage.padRight(combinedMessage.length() + windowSize, ' ')
    def displaySegment = paddedMessage.substring(offset as Integer, Math.min((offset + windowSize) as Integer, paddedMessage.length() as Integer))

    log.debug "Display Segment: $displaySegment"

    sendEvent(name: "message", value: displaySegment, displayed: true)

    def nextOffset = (offset + 1) % paddedMessage.length()

    log.debug "Scheduling next banner update. Next Offset: $nextOffset"

    runInMillis(((settings.flashDisappearTime ?: 2).toBigDecimal().floatValue() * 1000).toInteger(), "bannerMessage", [data: [offset: nextOffset]])
}

def refresh() {
    log.debug "Refresh called"
    sendEvent(name: "message", value: device.currentValue("message"), displayed: true)
    sendEvent(name: "message2", value: device.currentValue("message2"), displayed: true)
    sendEvent(name: "message3", value: device.currentValue("message3"), displayed: true)
}

Late to the party, but isn't that what ChatGPT would write?

1 Like