[RELEASE] Tasmota (Connect) for Sonoff, Tuya, SmartLife & other ESP8266 devices)

Check the Tasmota device console: You should find similar to these. If isn’t, then something is not right, and could be tricky to debug…

05:25:46.239 RUL: TELE-ENERGY#TOTAL performs "WebSend [192.168.1.207:39500] /?json={"StatusSNS":{"ENERGY":{"Total":"264.039"}}}"
05:25:46.800 RSL: stat/tasmota/RESULT = {"WebSend":"Done"}
05:25:46.816 RUL: TELE-ENERGY#VOLTAGE performs "WebSend [192.168.1.207:39500] /?json={"StatusSNS":{"ENERGY":{"Voltage":"246"}}}"
05:25:47.380 RSL: stat/tasmota/RESULT = {"WebSend":"Done"}
05:25:47.397 RUL: TELE-ENERGY#CURRENT performs "WebSend [192.168.1.207:39500] /?json={"StatusSNS":{"ENERGY":{"Current":"0.105"}}}"
05:25:47.963 RSL: stat/tasmota/RESULT = {"WebSend":"Done"}

Thanks for the reply @hongtat . So if my internet connection fails then I wouldn’t be able to control the Tasmota devices via Smartthings, right?

Thanks!

You wouldn’t be able to control Tasmota devices via ST, if internet connection fails.

this is only for wifi device?

i have Moes wall switch but is zigbee so not luck here, i am correct?

Yes. This is for wifi ESP8266 devices.

1 Like

Can you help us with zigbee version of switch

We will donate the developer with solutuin 30€ until now

Please if you have time check this thread

I am trying to monitor battery power via monitoring the VCC of ESP8266 (basically Vcc drops below 3V when the battery drops below 3.6V )
Using Tasmota 9.5.0 firmware ( with USE_ADC_VCC enabled) and HongTat DHT.
I can Vcc value posted via a console on the actual Tasmota device (STATE = {“Vcc”:3.438}.
Modified and published the DHT code in my IDE to show it up in the ST app.
Here is my issue - it would show up in a simulator but would not in the ST app.
I have tried to remove the device and re-add but still no luck.
I am no programmer by any means. :blush:

Any suggestions?

Here is the modified code:

/**
 *  Tasmota - Generic Switch
 *
 *  Copyright 2020 AwfullySmart.com - HongTat Tan
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

String driverVersion() { return "20210810" }
import groovy.json.JsonSlurper
metadata {
    definition(name: "Tasmota Generic Switch", namespace: "hongtat", author: "HongTat Tan", ocfDeviceType: "oic.d.switch", vid: "af06f1a5-45b6-39ee-86bb-7cbe15062491", mnmn: "SmartThingsCommunity") {
        capability "Actuator"
        capability "Health Check"
        capability "Switch"
        capability "Polling"
        capability "Refresh"
        capability "Sensor"
        capability "Signal Strength"
		
        attribute "lastSeen", "string"
        attribute "version", "string"
    }

    simulator {
    }

    preferences {
        section {
            input(title: "Device Settings",
                    description: "To view/update this settings, go to the Tasmota (Connect) SmartApp and select this device.",
                    displayDuringSetup: false,
                    type: "paragraph",
                    element: "paragraph")
            input(title: "", description: "Tasmota Generic Switch v${driverVersion()}", displayDuringSetup: false, type: "paragraph", element: "paragraph")
        }
    }

    tiles(scale: 2) {
        multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
            tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
                attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.light.on", backgroundColor: "#00A0DC"
                attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.light.off", backgroundColor: "#ffffff"
            }
        }

        standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh"
        }
        standardTile("lqi", "device.lqi", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state "default", label: 'LQI: ${currentValue}'
        }
        standardTile("rssi", "device.rssi", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state "default", label: 'RSSI: ${currentValue}dBm'
        }
		standardTile("Vcc", "device.Vcc", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
            state "default", label: 'Vcc: ${currentValue}V'
         }   
        main "switch"
        details(["switch", "refresh", "lqi", "rssi", "Vcc"])
    }
}

def installed() {
    sendEvent(name: "checkInterval", value: 30 * 60 + 2 * 60, displayed: false, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID])
    sendEvent(name: "switch", value: "off")
    log.debug "Installed"
    response(refresh())
}

def uninstalled() {
    sendEvent(name: "epEvent", value: "delete all", isStateChange: true, displayed: false, descriptionText: "Delete endpoint devices")
}

def updated() {
    initialize()
}

def initialize() {
    if (device.hub == null) {
        log.error "Hub is null, must set the hub in the device settings so we can get local hub IP and port"
        return
    }
    // Child creation
    String childMeta = getDataValue("child")
    if (childMeta != null && ((childMeta.startsWith("{") && childMeta.endsWith("}")) || (childMeta.startsWith("[") && childMeta.endsWith("]")))) {
        def json = new JsonSlurper().parseText(childMeta)
        if (json != null) {
            boolean hasError = false
            json.each { i,tasmota ->
                try {
                    String dni = "${device.deviceNetworkId}-ep${i}"
                    addChildDevice(tasmota, dni, device.getHub().getId(),
                            [completedSetup: true, label: "${device.displayName} ${i}", isComponent: false])
                    log.debug "Created '${device.displayName}' - ${i}ch (${tasmota})"
                } catch (all) {
                    hasError = true
                    log.error "Error: ${(all as String).split(":")[1]}."
                }
            }
            if (hasError == false) {
                updateDataValue("child","")
            }
        }
    }

    def syncFrequency = (parent.generalSetting("frequency") ?: 'Every 1 minute').replace('Every ', 'Every').replace(' minute', 'Minute').replace(' hour', 'Hour')
    try {
        "run$syncFrequency"(refresh)
    } catch (all) { }
    sendEvent(name: "checkInterval", value: parent.checkInterval(), displayed: false, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID])

    parent.callTasmota(this, "Status 5")
    parent.callTasmota(this, "Backlog Rule1 ON Power#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER\":\"%value%\"}} ENDON ON Power1#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER1\":\"%value%\"}} ENDON ON Power2#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER2\":\"%value%\"}} ENDON ON Power3#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER3\":\"%value%\"}} ENDON ON Power4#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER4\":\"%value%\"}} ENDON;Rule1 1")
    parent.callTasmota(this, "Backlog Rule2 ON Power5#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER5\":\"%value%\"}} ENDON ON Power6#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER6\":\"%value%\"}} ENDON ON Power7#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER7\":\"%value%\"}} ENDON ON Power8#state DO WebSend ["+device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")+"] /?json={\"StatusSTS\":{\"POWER8\":\"%value%\"}} ENDON;Rule2 1")
    parent.callTasmota(this, "Status 8")
    refresh()
}

def parse(String description) {
    def events = null
    def message = parseLanMessage(description)
    def json = parent.getJson(message.header)
    if (json != null) {
        events = parseEvents(200, json)
    }
    return events
}

def calledBackHandler(physicalgraph.device.HubResponse hubResponse) {
    def events = null
    def status = hubResponse.status
    def json = hubResponse.json
    events = parseEvents(status, json)
    return events
}

def parseEvents(status, json) {
    def events = []
    if (status as Integer == 200) {
        def channel = getDataValue("endpoints")?.toInteger()
        def eventdateformat = parent.generalSetting("dateformat")
        def now = location.timeZone ? new Date().format("${eventdateformat}a", location.timeZone) : new Date().format("yyyy MMM dd EEE h:mm:ss")

        // Power
        if (channel != null) {
            for (i in 0..channel) {
                def number = (i > 0) ? i : ""
                def power = (json?.StatusSTS?."POWER${number}" != null) ? (json?.StatusSTS?."POWER${number}") : ((json?."POWER${number}" != null) ? json?."POWER${number}" : null)

                def powerStatus = null
                if (power in ["ON", "1"]) {
                    powerStatus = "on"
                } else if (power in ["OFF", "0"]) {
                    powerStatus = "off"
                }
                if (powerStatus != null) {
                    if ((channel == 1) || (channel > 1 && i == 1)) {
                        events << sendEvent(name: "switch", value: powerStatus)
                    } else {
                        String childDni = "${device.deviceNetworkId}-ep$i"
                        def child = childDevices.find { it.deviceNetworkId == childDni }
                        child?.sendEvent(name: "switch", value: powerStatus)
                    }
                    log.debug "Switch $number: '$powerStatus'"
                }
            }
        }

        // Temperature, Humidity (Status 8)
        def resultTH = null
        if (json?.StatusSNS != null) {
            for (record in json.StatusSNS) {
                if (record.value instanceof Map && (record.value.containsKey("Humidity") || record.value.containsKey("Temperature"))) {
                    resultTH = record.value
                }
            }
            if (resultTH != null) {
                def childMessage = [:]
                if (resultTH.containsKey("Humidity")) {
                    childMessage.humidity = Math.round((resultTH.Humidity as Double) * 100) / 100
                }
                if (resultTH.containsKey("Temperature")) {
                    childMessage.temperature = resultTH.Temperature.toFloat()
                }
                if (json?.StatusSNS?.TempUnit != null) {
                    childMessage.tempUnit = json?.StatusSNS?.TempUnit
                }
                def child = childDevices.find { it.typeName == "Tasmota Child Temp/Humidity Sensor" }
                child?.parseEvents(200, childMessage)
            }
        }

        // MAC
        if (json?.StatusNET?.Mac != null) {
            def dni = parent.setNetworkAddress(json.StatusNET.Mac)
            def actualDeviceNetworkId = device.deviceNetworkId
            if (actualDeviceNetworkId != state.dni) {
                runIn(10, refresh)
            }
            log.debug "MAC: '${json.StatusNET.Mac}', DNI: '${state.dni}'"
            if (state.dni == null || state.dni == "" || dni != state.dni) {
                if (channel > 1 && childDevices) {
                    childDevices.each {
                        it.deviceNetworkId = "${dni}-ep" + parent.channelNumber(it.deviceNetworkId)
                        log.debug "Child: " + "${dni}-ep" + parent.channelNumber(it.deviceNetworkId)
                    }
                }
            }
            state.dni = dni
        }

        // Signal Strength
        if (json?.StatusSTS?.Wifi != null) {
            events << sendEvent(name: "lqi", value: json?.StatusSTS?.Wifi.RSSI, displayed: false)
            events << sendEvent(name: "rssi", value: json?.StatusSTS?.Wifi.Signal, displayed: false)
            
         }
          // Vcc
        if (json?.StatusSTS?.Vcc != null) {
            events << sendEvent(name: "Vcc", value: json?.StatusSTS?.Vcc, displayed: false)
        }


        // Version
        if (json?.StatusFWR?.Version != null) {
            state.lastCheckedVersion = new Date().getTime()
            events << sendEvent(name: "version", value: json.StatusFWR.Version, displayed: false)
        }

        // Call back
        if (json?.cb != null) {
            parent.callTasmota(this, json.cb)
        }

        // Last seen
        events << sendEvent(name: "lastSeen", value: now, displayed: false)
    }
    return events
}

def on() {
    def channel = getDataValue("endpoints")?.toInteger()
    parent.callTasmota(this, "POWER" + ((channel == 1) ? "" : 1) + " 1")
}

def off() {
    def channel = getDataValue("endpoints")?.toInteger()
    parent.callTasmota(this, "POWER" + ((channel == 1) ? "" : 1) + " 0")
}

def refresh(dni=null) {
    def lastRefreshed = state.lastRefreshed
    if (lastRefreshed && (now() - lastRefreshed < 5000)) return
    state.lastRefreshed = now()

    // Check version every 30m
    def lastCheckedVersion = state.lastCheckedVersion
    if (!lastCheckedVersion || (lastCheckedVersion && (now() - lastCheckedVersion > (30 * 60 * 1000)))) {
        parent.callTasmota(this, "Status 2")
    }

    def actualDeviceNetworkId = device.deviceNetworkId
    if (state.dni == null || state.dni == "" || actualDeviceNetworkId != state.dni) {
        parent.callTasmota(this, "Status 5")
    }
    parent.callTasmota(this, "Status 8")
    parent.callTasmota(this, "Status 11")
}

def ping() {
    refresh()
}

def childOn(dni) {
    parent.callTasmota(this, "POWER" + parent.channelNumber(dni) + " 1")
}

def childOff(dni) {
    parent.callTasmota(this, "POWER" + parent.channelNumber(dni) + " 0")
}

Does the Generic Metering Switch dth work for you? It has voltage.

I want to measure internal core VCC voltage not the external one, which usually is using A0 GPIO.
The solution was found and one great samaritan (Nayely Zarazua) help me to accomplish this.
Details are here

@hongtat will tasmota connect go away when smartthings ends support for groovy?

Yes. It will.

Whether there would be a replacement for it, I’m unable to provide any specifics yet…

Thank you @hongtat for the reply, hopefully you can make a replacement.

@hongtat

Is there a way to monitor DC voltage using a esp8266 by using A0 ( analog input ) and have it displayed on Smartthings using a device handler .? I have currently set my ESP8266 to generic, its the only setting mode that shows the GPI018 ( set to ADC Range ) . Im looking to monitor my trailer 12v battery voltage when its parked next to my house.

Thanks !

maybe my question is stupid and inappropriate, but I try to ask it anyway. Could this project have a sequel by integrating a new edge driver for tasmota devices even if in wifi?

There’s no such thing as a stupid question.

Yes, a new edge driver for Tasmota is in the works.

7 Likes

Hi, I have flashed my Sonoff Basic with Tasmota 10.0.0. I have added the DTH and the Sonoff (Connect) Smart App to my SmartThings Groovy IDE. I have added DTH and Smart Apps like this many times before, so I’m pretty confident in navigating Git Hub, Groovy etc. The device has been discovered by Alexa (by emulating the Hue Hub). I can also connect to the Sonoff Basic through the Sonoff Web Server and toggle power, configure, etc.

What I cannot get done however is to get the Smartthings app to show the Sonoff (Connect) smart app. I am using the new Smartthings app (ver 1.7.73.22). It simply refuses to see it. My other Groovy listed Smart Apps are shown in the SmartThings app, just not this one. The “new” SmartThings app was ported over from SmartThings Classic, which I no longer have installed and it will not allow me to reinstall, even though I have the apk for the SmartThings Classic app, so using SmartThings Classic app is not an option for me at this time.

I cannot add the my newly flashed Sonoff Basic to SmartThings.

Is there something I am not doing correctly? Any help would be greatly appreciated, as I am somewhat anal about this kind of thing and it’s driving me crazy!!!

Martin, I had the same issue! I’m no expert, but this may help:
1.) Click on ‘automations’ at the bottom of the app
2.) Click the + at the top
3.) Select "add routine’
4.) At the bottom, select ‘discover’.
5.) Scroll to the bottom. Your samsung “smartapps” should be listed here.
6.) Select Tasmota (Connect)

1 Like

I’m having trouble adding window/door sensors (magnetic reed switches). I have a handful of nodemcu and d1 minis. I believe I have the up-to-date tasmota github on samsung IDE (v10). flashed the devices with the easy webflash program at Install Tasmota. I add my local wifi network and can see the webui. I have tried to change the configuration template and module in several different ways using the usable pins (ie gpi12,13,14). I can add the device to tasmota connect in ST(new) app. It ALWAYS shows up as 1 on/off switch. Never shows up as more than one switch or any other device such as a contact sensor.

Side note, I use alexa for voice integration. Once I add via tasmota connect, the device auto populates in alexa as well. If I have more than one switch, I can go back to alexa and ‘discover devices’ and it adds the remaining switches. But I can’t ever add sensors. I also can’t add other switches via smartthings. I’m guessing it’s something wrong with parent/child issues, but I am a newb with code. Any help would be appreciated!

OMG!!! I have looked and looked in the new Smartthings app, and never found this!
Thank you so much!!! I did what you said, and there it was! Now working! Thanks again!

No worries! I struggled with adding it myself, just the other day. Glad I could help.