Giex Zigbee Sprinkler Valve


Does anybody use Giex Valves ? I have an issue with reading the logs. Hub C8, Sprinkler 4 was open this morning but the log looks confusing with the disabled commands. Sprinkler 4 is the closest to the hub and it didn't open with a few test runs yesterday, but it looks like it was open this morning. The Auto Off timer and Irrigation Capacity shut off don't work, but I guess this valves don't support that feature. I’m confused where it says “Valve state is disabled”

Also
I have a rain gauge modified with a zigbee door sensor, it counts the rain amount and send a signal via Zigbee. I count the clicks in Variables. Is there a way to send these variables constantly to a computer e.g. that I could calculate and see the rain amount e.g. in microsoft access.

Thanks

I believe this is the rabbit hole you are seeking. I have used Giex hose valves in the past, but it has been 9 months or so. They are currently boxed up for a move, so it is tough to provide much more first person info. The thread linked will give you some insight, though.

I have a giex hose valve too, works well with the driver in that linked thread.

Currently running 6 Geix GS02’s here (it’s a large house), all working flawlessly with kkossev’s Tuya driver linked above.

I haven’t tried the volume-based shutoff on these, but the time-based shutoffs work just fine. Use the “Auto off timer (Irrigation Duration)” parameter on the Preferences page for the device, with the time in seconds.

I have one, but mine is all grey in color. It didn't work so great in Hubitat, but with smartlife or HA it works excellent, capacity, duration , schedules, etc.

Change your driver to "device" and click get info button, post the fingerprint here so we can check if it's found in the driver by @kkossev

Probably not necessary. As I said (and a couple other people as well), the giex gx-02 works just fine with the driver already.

My thinking was, as with many veried revisions of Tuya chips, his valve might be slightly distinct.
In any event I had to pair mine close to the hub, then moved it to its final location.

I’m sure that’s possible.

My personal approach would be to first try the driver that a few people have already suggested should work. Then only if needed, go through the extra steps of additional driver changes with the goal of pinning down the device’s fingerprint to then share here and wait for an update to the driver.

To each their own, though.

I have three of those that I bought last year, and they are still working so far this year.

My only issue with them has been that they go offline. I have issues with Zigbee through my outside wall anyway, but most Zigbee stuff works about 20 feet from the hub outside.

Even with these valves within 10 feet of the hub (through one interior wall, and one exterior), they drop probably every two weeks or so. All my Zigbee stuff in the greenhouse stays connected at about 20 feet.

So, I have to hold the button and get the light flashing, and run pairing to put them back on network (they fall right back into place and start functioning again). Sometimes they go offline when the valve is open, and that is my biggest issue with them, as nothing can turm them off digitally at that point.

I wouldn't try to send them off the hub for processing, that can all happen in a simple app and a device. That is a good automation for AI to create, to make you an actual rainMeter device, based on your contact sensor rain counter.

An app can subscribe to the contact sensor and count every open event per hour, and daily, and give you rain rate every time it updates based on a setting for what one open event is for rain inches. It can put those values in a virtual child device in the form of attributes, such as rainHourly, rainDaily, and rainRate. Then you can retrieve those values live in other automations.

I took a minute to write a query and get it started, if interested. Here is the code if you want to try testing it and feeding back to AI to get it working. I may play around with it myself when I have some time and get AI to fix up any issues.

/**
 *  Rain Gauge Counter
 *
 *  Counts contact openings as rain tips, accumulates hourly and daily totals,
 *  and computes the current rain rate. Updates a child device with attributes:
 *  rainHourly, rainDaily, and rainRate.
 *
 *  Author: Your Name
 *  Date: 2026-06-19
 */

definition(
    name: "Rain Gauge Counter",
    namespace: "com.example",
    author: "Your Name",
    description: "Counts contact opens as rain tips and calculates rain totals and rate.",
    category: "Weather",
    iconUrl: "",
    iconX2Url: ""
)

preferences {
    input name: "contactSensor", type: "capability.contactSensor", title: "Contact Sensor", required: true
    input name: "inchesPerEvent", type: "decimal", title: "Inches of rain per open event", defaultValue: 0.01, required: true
}

def installed() {
    initialize()
}

def updated() {
    unsubscribe()
    initialize()
}

def initialize() {
    // Subscribe to the contact sensor's 'contact' event
    subscribe(contactSensor, "contact", contactHandler)

    // Schedule resets at the top of every hour (0 minutes)
    schedule("0 0 * * * ?", hourlyReset)

    // Create the child device (using our custom driver)
    createChildDevice()

    // Initialize state variables if they are null
    if (state.hourlyTotal == null) state.hourlyTotal = 0.0
    if (state.dailyTotal == null) state.dailyTotal = 0.0
    if (state.lastEventTime == null) state.lastEventTime = null
    if (state.lastRate == null) state.lastRate = 0.0

    // Set initial values on the child device
    updateChildDevice(state.hourlyTotal, state.dailyTotal, state.lastRate)
}

/**
 * Create a child device using our custom driver.
 * Driver namespace: "com.example", driver name: "Rain Meter Child"
 */
def createChildDevice() {
    def networkId = "rainMeter-${app.id}"
    def child = getChildDevice(networkId)
    if (!child) {
        try {
            child = addChildDevice("com.example", "Rain Meter Child", networkId, [
                label: "Rain Meter",
                isComponent: false
            ])
            log.info "Child device 'Rain Meter' created."
        } catch (e) {
            log.error "Failed to create child device: ${e.message}"
        }
    }
}

/**
 * Handler for contact sensor events.
 * Only processes 'open' events as rain tips.
 */
def contactHandler(evt) {
    if (evt.value == "open") {
        def now = new Date().time
        def inches = inchesPerEvent.toDouble()

        // Update totals
        state.hourlyTotal = (state.hourlyTotal ?: 0.0) + inches
        state.dailyTotal = (state.dailyTotal ?: 0.0) + inches

        // Compute rain rate (inches per hour) based on time since last tip
        def rate = 0.0
        if (state.lastEventTime != null) {
            def deltaMs = now - state.lastEventTime
            if (deltaMs > 0) {
                def deltaHours = deltaMs / 3600000.0
                rate = inches / deltaHours
            } else {
                // If zero time elapsed, keep previous rate or set to 0
                rate = state.lastRate ?: 0.0
            }
        } else {
            // First event: rate is undefined, keep 0
            rate = 0.0
        }
        state.lastEventTime = now
        state.lastRate = rate

        // Update child device
        updateChildDevice(state.hourlyTotal, state.dailyTotal, rate)
    }
}

/**
 * Scheduled job that runs at the top of every hour.
 * Resets the hourly total, and also resets the daily total at midnight.
 */
def hourlyReset() {
    state.hourlyTotal = 0.0

    def now = new Date()
    // Check if it's exactly midnight
    if (now.getHours() == 0 && now.getMinutes() == 0) {
        state.dailyTotal = 0.0
    }

    // Keep the last computed rate, or set to 0 if not available
    def rate = state.lastRate ?: 0.0
    updateChildDevice(state.hourlyTotal, state.dailyTotal, rate)
}

/**
 * Sends events to the child device to update its attributes.
 */
def updateChildDevice(hourly, daily, rate) {
    def networkId = "rainMeter-${app.id}"
    def child = getChildDevice(networkId)
    if (child) {
        child.sendEvent(name: "rainHourly", value: hourly, unit: "in")
        child.sendEvent(name: "rainDaily", value: daily, unit: "in")
        child.sendEvent(name: "rainRate", value: rate, unit: "in/hr")
    } else {
        log.warn "Child device not found; attempting to recreate."
        createChildDevice()
        // Retry once
        child = getChildDevice(networkId)
        if (child) {
            child.sendEvent(name: "rainHourly", value: hourly, unit: "in")
            child.sendEvent(name: "rainDaily", value: daily, unit: "in")
            child.sendEvent(name: "rainRate", value: rate, unit: "in/hr")
        }
    }
}

/**
 *  Rain Meter Child Device
 *
 *  Provides attributes for rainHourly, rainDaily, and rainRate.
 *  Receives updates from the parent Rain Gauge Counter app.
 *
 *  Author: Your Name
 *  Date: 2026-06-19
 */

metadata {
    definition(name: "Rain Meter Child", namespace: "com.example", author: "Your Name") {
        capability "Sensor"

        // Custom attributes
        attribute "rainHourly", "number"
        attribute "rainDaily", "number"
        attribute "rainRate", "number"

        // Optionally display these in the UI
        command "refresh"
    }

    // Optional: tile definitions for a clean device page
    tiles(scale: 2) {
        multiAttributeTile(name:"rainTotals", type:"generic", width:6, height:4) {
            tileAttribute("device.rainHourly", key: "PRIMARY_CONTROL") {
                attributeState("number", label:'${value} in/hr', icon:"st.Weather.weather2")
            }
            tileAttribute("device.rainDaily", key: "SECONDARY_CONTROL") {
                attributeState("number", label:'Daily: ${value} in')
            }
        }
        valueTile("rainRate", "device.rainRate", width:2, height:2) {
            state("number", label:'Rate: ${value} in/hr')
        }
        main "rainTotals"
        details(["rainTotals", "rainRate"])
    }
}

/**
 * Called when the device is installed or updated.
 * Not strictly required for receiving events, but good practice.
 */
def installed() {
    initialize()
}

def updated() {
    initialize()
}

def initialize() {
    // Set default values if they haven't been set yet
    if (device.currentValue("rainHourly") == null) {
        sendEvent(name: "rainHourly", value: 0.0, unit: "in")
    }
    if (device.currentValue("rainDaily") == null) {
        sendEvent(name: "rainDaily", value: 0.0, unit: "in")
    }
    if (device.currentValue("rainRate") == null) {
        sendEvent(name: "rainRate", value: 0.0, unit: "in/hr")
    }
}

/**
 * Optional refresh command – pushes current states again.
 */
def refresh() {
    def hourly = device.currentValue("rainHourly") ?: 0.0
    def daily = device.currentValue("rainDaily") ?: 0.0
    def rate = device.currentValue("rainRate") ?: 0.0
    sendEvent(name: "rainHourly", value: hourly, unit: "in")
    sendEvent(name: "rainDaily", value: daily, unit: "in")
    sendEvent(name: "rainRate", value: rate, unit: "in/hr")
}

// No parse() needed – events are pushed from the parent via sendEvent.

It's possible to do it in RM too. I have the same rain gauge setup and track rain amounts for the last day, week, month and year within RM then display these values on a Dashboard.