ESPHome + Hubitat

Would this Ensto thermostat work with this? Install groove from this thread and code from link this to device? Is it that simple or what did I miss?

Any chance you could add direct support for ESPresence? Even if it requires an external MQTT broker, it would still make working directly with ESPresence sensors a million time easier than importing them via HABridge and then having to create RM rules to translate states (I think).

I'd be happy to help with the testing, and I have plenty of them to test against.

I don't think ESPresence is under the umbrella of ESPHome. It wouldn't make sense to include it in this driver.

1 Like

I was under the impression that it uses most of the same mechanisms s ESPhome to communicate, ie MQTT and from a HA point of view, the presence sensors work roughly the same.

I believe the HA implementation of ESPresense depends entirely on MQTT, but these drivers connect directly to the ESP devices. Unfortunately, I don't think it would be trivial to recreate the mqtt_room implementation here.

That’s a shame, I’d love to shut down my HA vm.

Well, I received my RATGDO, flashed it, and installed it.

Using the ESPHome Garage Door driver, it worked on the first try.

Curious to know if you are able to control the lights and get the status of the motion sensors, @672southmain and @sky320?

I’m in the process of trying the different drivers to see if some will work, but if there is one (or multiple?) that are known to work, I will likely use them! :blush:

My LiftMaster 8365-267 GDO with 828LM Internet Gateway doesn’t have motion sensor. I’ve only tried door open/close. Hookup and firmware flashing was straightforward, as you experienced.

I haven’t had the time to put it on the HE dashboard, mainly because we don’t use dashboards. Surgery in November, and recovery afterwards, has slowed me down a bit, don’t feel at ease climbing on a ladder right now.

It’s a well done integration, package, and documentation.

1 Like

I can imagine! Hopefully the recovery will continue until you are back to your old self.

I’m using my RATGDO with the wall mounted Garage Door opener. The direct web interface has the ability to turn on/off the light, detect motion and also if the obstruction is blocking the sensors. I’ll be looking forward to figuring out how to enable these in Hubitat.

1 Like

Well, I do have an obstruction sensor (electric eye about 3 inches from floor on sides of door). Seems to work, I just hooked up the wires according to the wiring diagram.

The integration and hardware are very well done, self configuring.

Indeed!

Are you able to see if there is an obstruction within Hubitat? I can see it in the RATGDO’s web interface, but not in Hubitat…

I believe so.

It’s too cold right now (8 degrees F and 6 inches snow, still coming down) to go out and test.

Lol - Indeed!!!

I think I didn’t setup my driver correctly… I set it up as ā€œESPHome Garage Doorā€ but I don’t see child devices. I’ve not had success in fixing it…

If I may ask - When you setup your device, which driver did you initially use? ESPHome Garage Door, or another one? (Should show in the Parent device’s screen).

I’ll see if I can set it up with that same driver. I suspect this is my issue, and I tried most ESPHome drivers, but didn’t pay attention for children… or wait for them to be created possibly…

I brought RatGDO into Hubitat via HADB from HA Yellow, ESP Home integration. I have also installed the ESP Home integration on Hubitat via HPM, and installed the Hubitat ESP Home Garage Door Opener (virtual device, then configured to talk to the RatGDO IP). That virtual device successfully configured. There are no child devices on the Hubitat ESP Garage Door.

So, I have two paths to the RatGDO - one that is direct through the Hubitat ESP Integration, and another through HADB to HA Yellow’s ESP Home integration.

I looked at the code for the Hubitat Garage Door driver for ESP Home, and it seems basic, has no obstruction sensor. The screenshot I showed was the RatGDO child device from HADB, which is full-featured.

Ah! That explains it.

I was hoping to be able to control and access all functionality directly via the ESPHome driver… Not looking like this will be possible…? (I’ve never used or had HA setup…)

I guess unless @jonathanb is still around and would be interested to update the driver, or someone else knows what modifications would be required, it will only open and close for me.

I could probably change to the MQTT driver, but the extra complication related to the MQTT server is a bit daunting for me, and especially now that the basic functionality works via ESPHome.

All I’ve used HA for are integrations that are non-existent or abandoned on Hubitat. I’ve found it rather straightforward.

While I have tried both the Aeotec Z-Pi 7 and Zooz ZAC93 Z-Wave 800 controller on my HA Yellow, it’s only been for testing and experimentation. Everything stays on Hubitat, and I just bring those few cloud (and now, RatGDO) devices in via HADB.

Again, it’s rather straightforward, I suspect because I just bought an HA Yellow and plugged it in, much like Hubitat.

1 Like

I'm trying to add Temperature & Humidity sensors to ESPHome Multi Switch & Contact Sensor.
Values are displayed in the parent's current state, but they are not updated. what am i doing wrong?

/**
 *  MIT License
 *  Copyright 2022 Jonathan Bradshaw (jb@nrgup.net)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */
metadata {
    definition(
        name: 'ESPHome Multi Switch - Contact Sensor - TH ',
        namespace: 'esphome',
        author: 'Jonathan Bradshaw',
        singleThreaded: true,
        importUrl: '') {

        capability 'Refresh'
        capability 'Initialize'
        capability 'SignalStrength'
        capability 'Sensor'
        capability 'RelativeHumidityMeasurement'
        capability 'TemperatureMeasurement'

        // attribute populated by ESPHome API Library automatically
        attribute 'networkStatus', 'enum', [ 'connecting', 'online', 'offline' ]
    }

    preferences {
        input name: 'ipAddress',    // required setting for API library
                type: 'text',
                title: 'Device IP Address',
                required: true

        input name: 'password',     // optional setting for API library
                type: 'text',
                title: 'Device Password <i>(if required)</i>',
                required: false

        input name: 'logEnable',    // if enabled the library will log debug details
                type: 'bool',
                title: 'Enable Debug Logging',
                required: false,
                defaultValue: false

        input name: 'logTextEnable',
              type: 'bool',
              title: 'Enable descriptionText logging',
              required: false,
              defaultValue: true
    }
}

import com.hubitat.app.DeviceWrapper
import com.hubitat.app.ChildDeviceWrapper

public void initialize() {
    // API library command to open socket to device, it will automatically reconnect if needed
    openSocket()

    if (logEnable) {
        runIn(1800, 'logsOff')
    }
}

public void installed() {
    log.info "${device} driver installed"
}

public void logsOff() {
    espHomeSubscribeLogs(LOG_LEVEL_INFO, false) // disable device logging
    device.updateSetting('logEnable', false)
    log.info "${device} debug logging disabled"
}

// driver commands
public void componentOn(DeviceWrapper dw) {
    String key = dw.getDeviceNetworkId().minus("${device.id}-")
    if (dw.currentValue('switch') != 'on') {
        if (logTextEnable) { log.info "${device} on" }
        espHomeSwitchCommand(key: key as Long, state: true)
    }
}

public void componentOff(DeviceWrapper dw) {
    String key = dw.getDeviceNetworkId().minus("${device.id}-")
    if (dw.currentValue('switch') != 'off') {
        if (logTextEnable) { log.info "${device} off" }
        espHomeSwitchCommand(key: key as Long, state: false)
    }
}

public void refresh() {
    log.info "${device} refresh"
    state.clear()
    state.requireRefresh = true
    espHomeDeviceInfoRequest()
}

public void updated() {
    log.info "${device} driver configuration updated"
    initialize()
}

public void uninstalled() {
    closeSocket('driver uninstalled') // make sure the socket is closed when uninstalling
    log.info "${device} driver uninstalled"
}

// the parse method is invoked by the API library when messages are received
public void parse(Map message) {
    if (logEnable) { log.debug "ESPHome received: ${message}" }

    switch (message.type) {
        case 'device':
            // Device information
            break

        case 'entity':
            // Discover all binary switches and create child devices for each
            if (message.platform == 'switch' && !message.disabledByDefault && message.entityCategory == 'none') {
                String dni = "${device.id}-${message.key}"
                ChildDeviceWrapper dw = getChildDevice(dni) ?:
                    addChildDevice(
                        'hubitat',
                        'Generic Component Switch',
                        dni
                    )
                dw.name = message.objectId
                dw.label = message.name
            }

            // Discover all binary sensors and create child devices for each
            if (message.platform == 'binary' && !message.disabledByDefault && message.entityCategory == 'none') {
                String dni = "${device.id}-${message.key}"
                ChildDeviceWrapper dw = getChildDevice(dni) ?:
                    addChildDevice(
                        'hubitat',
                        'Generic Component Contact Sensor',
                        dni
                    )
                dw.name = message.objectId
                dw.label = message.name
            }

            if (message.platform == 'sensor') {
                switch (message.deviceClass) {
                    case 'signal_strength':
                        state['signalStrength'] = message.key
                        break
                    case 'humidity':
                        // This will populate the cover dropdown with all the entities
                        // discovered and the entity key which is required when sending commands
                        state.sensors = (state.sensors ?: [:]) + [ (message.key): message ]
                        if (!settings.humidity) {
                            device.updateSetting('humidity', message.key)
                        }
                        break
                    case 'temperature':
                        // This will populate the cover dropdown with all the entities
                        // discovered and the entity key which is required when sending commands
                        state.sensors = (state.sensors ?: [:]) + [ (message.key): message ]
                        if (!settings.temperature) {
                            device.updateSetting('temperature', message.key)
                        }
                        break
                }
                return
            }
            break

        case 'state':
            // Check if the entity key matches the message entity key received to update device state
            if (settings.temperature as Long == message.key && message.hasState) {
                String value = message.state
                if (device.currentValue('temperature') != value) {
                    sendEvent([
                        name: 'temperature',
                        value: value,
                        descriptionText: "Temperature is ${value}"
                    ])
                }
                return
            }

            if (settings.humidity as Long == message.key && message.hasState) {
                String value = message.state
                if (device.currentValue('humidity') != value) {
                    sendEvent([
                        name: 'humidity',
                        value: value,
                        unit: '%',
                        descriptionText: "Humidity is ${value}"
                    ])
                }
                return
            }
            
            // Signal Strength
            if (state.signalStrength as Long == message.key && message.hasState) {
                Integer rssi = Math.round(message.state as Float)
                String unit = 'dBm'
                if (device.currentValue('rssi') != rssi) {
                    descriptionText = "${device} rssi is ${rssi}"
                    sendEvent(name: 'rssi', value: rssi, unit: unit, descriptionText: descriptionText)
                    if (logTextEnable) { log.info descriptionText }
                }
                return
            }

            // Receives entity state updates to send to child device
            if (message.platform == 'switch') {
                String dni = "${device.id}-${message.key}"
                String type = message.isDigital ? 'digital' : 'physical'
                String value = message.state ? 'on' : 'off'
                getChildDevice(dni)?.parse([
                    [ name: 'switch', value: value, type: type, descriptionText: "switch is ${value}" ]
                ])
                return
            }

            // Receives entity state updates to send to child device
            if (message.platform == 'binary' && message.hasState) {
                String dni = "${device.id}-${message.key}"
                String type = message.isDigital ? 'digital' : 'physical'
                String value = message.state ? 'closed' : 'open'
                getChildDevice(dni)?.parse([
                    [ name: 'contact', value: value, type: type, descriptionText: "contact is ${value}" ]
                ])
                return
            }
            break
    }
}

// Put this line at the end of the driver to include the ESPHome API library helper
#include esphome.espHomeApiHelper

Solved the TH values update problem. But now I can't get values rounded to 1 decimal.

filters:
    - round: 1 # will round to 1 decimal place

round filter is not recognized in the sensor (bme280)

I tried lambda, but the most I could get was an integer

filters:
      - lambda: return round(x);

this doesn't work

filters:
      - lambda: return round(x, 1);

Partially solved the round problem: round function is recognized updating esphome over v.2023.11.

With filters: - round: 1 sometimes I still get values with multi decimals.

Do you know how to truncate to 1 decimal in esphome or in the driver?

FYI, after a day of trial and error, to get a round value you have to modify the string value in the driver:

String value = message.state
// mod
valuernd = String.format(Locale.US, "%.1f", Float.valueOf(value));