[RELEASE] MQTT UA Client driver(switch, ir blaster) | tasmota

Actually, the rest API allows for the same feedback from the device to allow you to confirm if the action took place or not. The current version of the driver that I am using allows for capture of local changes as well as positive feedback from the device when a command is issued.

// Original driver developed by Brett Sheleski.
// Ported to Hubitat and updated to include switchNumber by ryan780.
metadata {
definition(name: "Sonoff-Tasmota RPC", namespace: "ryan780", author: "ryan780") {
capability "Actuator"
capability "Switch"
capability "Momentary"
capability "Polling"
capability "Refresh"
}

preferences {		
	section("Sonoff Host") {
    input(name: "ipAddress", type: "string", title: "IP Address", displayDuringSetup: true, required: true)
	input(name: "port", type: "number", title: "Port", displayDuringSetup: true, required: true, defaultValue: 80)
    input(name: "switchNumber", type: "number", title: "Switch Number", displayDuringSetup: true, required: false, defaultValue: null)
	}

	section("Authentication") {
		input(name: "username", type: "string", title: "Username", displayDuringSetup: false, required: false)
		input(name: "password", type: "password", title: "Password (sent cleartext)", displayDuringSetup: false, required: false)
	}
	section("Logging"){
		input(name: "logEnable", type: "bool", title: "Debug Logging", required: false, defaultValue: false)
    }
}
}
 

def parse(String description) {
def message = parseLanMessage(description)

// parse result from current and legacy formats
def resultJson = {}
if (message?.json) {
	// current json data format
	resultJson = message.json
if (logEnable) log.debug resultJson
}
else {
	// legacy Content-Type: text/plain
	// with json embedded in body text
	def STATUS_PREFIX = "STATUS = "
	def RESULT_PREFIX = "RESULT = "
	if (message?.body?.startsWith(STATUS_PREFIX)) {
		resultJson = new groovy.json.JsonSlurper().parseText(message.body.substring(STATUS_PREFIX.length()))
	}
	else if (message?.body?.startsWith(RESULT_PREFIX)) {
		resultJson = new groovy.json.JsonSlurper().parseText(message.body.substring(RESULT_PREFIX.length()))
	}
	/* else if (message?.header?.contains("HTTP/1.1 200 OK")) {
		if (logEnable) log.debug $message?.header
	}*/
}

// consume and set switch state
if ((resultJson?."POWER$switchNumber" in ["ON", 1, "1"])) {
	setSwitchState(true)
}
else if ((resultJson?."POWER$switchNumber" in ["OFF", 0, "0"])) {
	setSwitchState(false)
}
else if ((resultJson?."POWER" in ["ON", 1, "1"])) {
	setSwitchState(true)
}
else if ((resultJson?."POWER" in ["OFF", 0, "0"])) {
	setSwitchState(false)
}
else {
//	log.error "can not parse result with header: $message.header"
//	log.error "...and raw body: $message.body"
}
}

def setSwitchState(Boolean on) {
if (logEnable) log.info "switch is " + (on ? "ON" : "OFF")
sendEvent(name: "switch", value: on ? "on" : "off")
}

def push() {
sendCommand("Power$switchNumber", "Toggle")
}

def on() {
sendCommand("Power$switchNumber", "On")
}

def off() {
sendCommand("Power$switchNumber", "Off")
}

def poll() {
sendCommand("Power$switchNumber", null)
}

def refresh() {
sendCommand("Power$switchNumber", null)
}

private def sendCommand(String command, String payload) {
if (logEnable) log.debug "sendCommand(${command}:${payload}) to device at $ipAddress:$port"

if (!ipAddress || !port) {
	log.warn "aborting. ip address or port of device not set"
	return null;
}
def hosthex = convertIPtoHex(ipAddress)
def porthex = convertPortToHex(port)

def path = "/cm"
if (payload){
	path += "?cmnd=${command}%20${payload}"
}
else{
	path += "?cmnd=${command}"
}

if (username){
	path += "&user=${username}"
	if (password){
		path += "&password=${password}"
	}
}

def result = new hubitat.device.HubAction(
	method: "GET",
	path: path,
	headers: [
		HOST: "${ipAddress}:${port}"
	]
)
return result
}

private String convertIPtoHex(ipAddress) {
String hex = ipAddress.tokenize( '.' ).collect { String.format( '%02x', it.toInteger() ) }.join()
return hex
}

private String convertPortToHex(port) {
String hexport = port.toString().format('%04x', port.toInteger())
return hexport
}

Ryan,
So The code above for the driver allows for a Tasmota device to work with HE with no Broker? (I presume the custom Tasmota FW referred to is also needed). Iā€™m not a code guy and just barely managed to flash my Tuya Smartlife device.

If device toggled outside of HE - dashboard won't know. In my case - all works

Yes it will. It is broadcast to HE with Eric's custom firmware. I am on my phone so I can't link to it at the moment.

I'm not a big fan of relying on custom firmware of Tasmota. Usually forks are not good in providing support. Community consolidated around main repo. I guess it's a slippery slope.
Also - there is no support for retaining messages, like mqtt has. I added this in my driver.
When client disconnected - broker will retain the message while reconnected client. Very helpful in crowded wifi networks

Okay. But you have to have a broker. Which is another thing to fail. I've never not had the other work.

That's why I'm looking for [API] Listen a TCP/UDP port from Driver?
For getting ability to build mqtt broker within hubitat

Mqtt broker can be installed as a cluster to multiple devices in the network for not fail

Then I have to have multiple devices to install it on.

And as far as firmware updates, as long as the device works, I'm not updating to the latest firmware for Tasmota. Why would i if the device works anyway?

Sure
It's easy to use all family mobile phones to do that, all android devices around(even TV boxes). (Just termux + termux api + termux boot + nodejs +...)
Or 2 HE hubs which makes sense anyway for not fighting with struggle of building mesh networks and supporting big number of ZigBee/zWave devices

Nope, nope and more nope. LOL. Sorry, but you're not selling me on MQTT for Tasmota. Not when there's a direct integration. Now, there are other reasons why i'd like MQTT support. But i don't see how you get a broker working natively on the hub without access to the OS. You can program one in Groovy?

Yes, there is a way to program one in groovy

Okay. I can't wait to see what you come up with.

Without API for building TCP services in HE I can come up with nothing

So, like i said, without access to the OS, you can't build a broker in the hub. :slight_smile:

Sure

I would pay for the developer access for the Built-in APP building opportunity

And they have said many times they will not ever do that. From a support perspective that would be a nightmare.

If keeping those drivers opensource - not necessarily

Native Hubitat drivers are not open source. You don't have access to the drivers released by Hubitat.