Skip to content
ggodart edited this page Feb 13, 2021 · 51 revisions

Introduction

Tasmota is custom firmware that is available for ESP8266 based devices allowing for web, timer, OTA firmware updates and sensor support. Tasmota provides ESP8266 based devices such as the Sonoff family or dev boards like the Wemos D1 mini a bi-directional interface via HTTP, MQTT and KNX.

The benefit of devices running Tasmota is that they leverage WiFi networks and thus use readily available, standards based networking equipment that can be extended to provides reliable communication. More importantly, the open source firmware means these devices do not rely on any cloud providers and are fully configurable and controllable with support for a large range of hardware and capabilities.

This page describes how to use Misterhouse with Tasmota devices via both HTTP and MQTT. For those unfamiliar with, please see this MQTT tutorial

Please be patient as it is currently a work-in-progress. The changes described below are in Misterhouse master as of 2020-12 and will make it into a future stable release in the future.

Installation and Configuration

Flashing your device with Tasmota is well documented on the internet:

The procedures above require GUI tools. It is also possible to install Tasmota on Sonoff DIY OTA devices (as of 2020-12 this includes Basic R3,RFR3 and Mini) with only the CLI using this procedure:

Plug in/turn on the device. When it boots, enter AP setup mode by holding the device button for 5+ seconds until the blue light begins to flash with a new pattern. If necessary, release and begin holding the device button again for 5+ seconds until the blue light begins to flash approx. twice per second. Then use a WiFi device, such as a smart phone, to connect to the Sonoff AP with SSID: ITEAD-xxxxxxx and password: 12345678

Use your WiFi device browser to visit http://10.10.7.1/ and set the correct WiFi AP parameters. The device will reboot and be reachable from the WiFi AP. Use this command to confirm the device is in DIY mode:

curl -X POST -H "Content-Type: application/json" -d '{"deviceid":"", "data":{}}' http://<sonoff_ip_address>:8081/zeroconf/info

If a response is received with no errors in the reply, then proceed to update the firmware. Note that the device will require internet access to perform the unlock.

Be sure to replace http://<server_ip>/<firmware_path>/tasmota-lite.bin with the right URL for your firmware server. Also update the sha256sum if you are not using release 9.1.0 by running:

sha256sum tasmota-lite.bin

When the Sonoff device boots use a WiFi device, such as a smart phone, to connect to the AP with SSID: ITEAD-xxxxxxx and password: 12345678

After the device connects to the WiFi AP run:

curl -X POST -H "Content-Type: application/json" -d '{"data":{}}' http://<sonoff_ip_address>:8081/zeroconf/ota_unlock
curl -X POST -H "Content-Type: application/json" -d '{"deviceid":"", "data":{"downloadUrl":"http://<server_ip>/<firmware_path>/tasmota-lite.bin", "sha256sum":"b8a16f18a018bd6233170ce28a625508c38770d9d8ef195c7afa50f914c4ac9c"}}' http://<sonoff_ip_address>:8081/zeroconf/ota_flash

Controlling Tasmota from Misterhouse using HTTP

Setting up Tasmota for HTTP

Tasmota devices can be controlled directly using HTTP GET request, for example: http://<tasmota_ip_address>/cm?cmnd=Power%201 and http://<tasmota_ip_address>/cm?cmnd=Power%200

Tasmota devices can also send status updates with HTTP GET requests, although this capability is not enabled by default and requires a rule to be added to the Tasmota device. To support basic single relay switching devices add the following rule:

Rule1 ON Power1#State DO WebSend [<mh_ip_address>:<mh_port>] /SET;none?select_item=<mh_item_name>&select_state=%value% ENDON

Where:
<mh_ip_address>:<mh_port> is the IPv4 address and port of the Misterhouse web interface (ex: 192.168.0.1:8081)
<mh_item_name> is the name of the item (ex: Kitchen_Light -- but don't include the leading '$')

The rule also needs to be enabled if it was not already:

Rule1 1

Adding Tasmota HTTP devices in Misterhouse

If you have a version of Misterhouse with Tasmota_HTTP_Item.pm (ex: master branch on or after 2020-12-17) you can define use the following configuration, in either an MHT file or a code file.

Define a TASMOTA_HTTP_SWITCH or a TASMOTA_HTTP_FAN in an MHT:

# TASMOTA_HTTP_SWITCH,   IP_address,  name,   POWER1,   groups
TASMOTA_HTTP_SWITCH,   192.168.1.10,   Kitchen_Light, POWER1,   Kitchen
#TASMOTA_HTTP_FAN,  IP_asddress,   name,    groups
TASMOTA_HTTP_FAN,   192.168.1.10,   Kitchen_fan,    Kitchen

Or a Tasmota_HTTP:Switch in a code file:

$Kitchen_Light = new Tasmota_HTTP::Switch("192.168.x.y","POWER1");

Where:
192.168.x.y is the IPv4 address or hostname of the Tasmota device Kitchen_Light is the name of the Misterhouse item POWER1 is the name of the Tasmota output to control (POWER1 if not specified) Kitchen is the group the item belongs to

Reload the code and the Tasmota device can be controlled like any other device. Ex:

$Kitchen_Light->set(ON);

Controlling Tasmota from Misterhouse using MQTT

MQTT Installation

First you will need to install an MQTT Broker and note down its IP address and port. These instructions were tested with Mosquitto on a raspberry PI.

Misterhouse Configuration

In order to define MQTT devices in your items.mht file you will need to make sure that your /lib/read_table_A.pl has the changes describe here and that you have the following entries in your mh.ini file.

# mandatory parameters for MQTT
CODE, require mqtt; #noloop
mqtt_host=192.168.1.10
mqtt_server_port=1883
mqtt_topic=stat/#
mqtt_debug=0

#optional parameters for MQTT
mqtt_LWT_topic=tele/Misterhouse/LWT
mqtt_LWT_payload=offine
mqtt_user=user 
mqtt_password=password 
mqtt_keepalive=120 

Then you can add MQTT items to your items.mht file as in the example below;

# MQTT_BROKER, name_of_broker
MQTT_BROKER, mqtt_1
# MQTT_DEVICE, name_of_device, groups, name_of_broker, topic
MQTT_DEVICE, MQTT_test, Gym, mqtt_1, cmnd/MQTT_test/power 

Tasmota Configuration

Point your browser at the Tasmota MQTT web interface on your device http://device_ip_address/mq? and add the mqtt broker's ip address, port and the Topic (MQTT_test in this example), leave the rest to default values. Then enable MQTT on the configure other page of the device http://device_ip_address/co?. Its a good idea to set a nice friendly name here at the same time, especially if you plan to have a number of devices.

You should now be able to control the device by any of the normal Misterhouse techniques, however there is no feedback about the actual state of the device. There is a number of ways to do this described below.

More advanced implementation notes

MQTT message case

By default, the Generic_item->set method converts values to lower case. If you are expecting to receive the same case as the MQTT messages, you need to set states_casesensitive for this device e.g.

$Workshop_cutout->{states_casesensitive} = 1;

Or in items.mht e.g.

CODE, $Workshop_cutout->{states_casesensitive} = 1;

Sonoff switches

Most Sonoff devices actually have 2 devices, a switch and a relay. By default the switch just toggles the relay locally and sends an mqtt message with a topic of stat/yourdevicetopic/POWER with a payload of ON or OFF. The simple way to handle this to ensure that your MH switch value correctly reflects the actual state of the device is to add another MH device e.g. MQTT_DEVICE, MQTT_test_status, Gym, mqtt_1, stat/MQTT_test/POWER. then have a state change handler in MH that syncs the two, e.g.

if ( $state = state_now $MQTT_test_status ) {
	my $new_state = $state;
	print_log("MQTT_test_status Switch changed to $new_state when relay is at " . $MQTT_test->{state});
	if ($new_state ne $MQTT_test->{state}) {
		$MQTT_test->set($new_state,"Local switch toggled");
	}
}

You can of course simplify this with a group if you have a lot of devices.\

If you have implemented wildcards as describe below, here is a more elegant way.

  1. add an mqtt wildcard device in items.mht e.g. MQTT_DEVICE, MQTT_switch_toggles, MQTT_device_toggles, mqtt_1, stat/+/SWITCH1T
  2. Set up a rule so that when the switch is pressed it publishes an appropriate message e.g.
on Switch1#state 
  do Publish stat/%topic%/SWITCH1T %value% 
endon
  1. Have a state change handler on the MQTT_switch_toggles misterhouse device that looks at the $MQTT_switch_toggles->{set_by_topic} to extract the name of the device it needs to toggle e.g.
if ( $state = state_now $MQTT_switch_toggles) {
    my @mqtt_message_bits = split( /\//, $MQTT_switch_toggles->{set_by_topic} );
    my $this_device       = $mqtt_message_bits[1];
    my $this_object       = get_object_by_name($this_device);
    if ( defined( $this_object->{object_name} ) ) {
       if ( $this_object->{"state"} eq ON ) {
            $this_object->set( OFF, "MQTT toggle" );
       }
       if ( $this_object->{"state"} eq OFF ) {
	    $this_object->set( ON, "MQTT toggle" );
       }
    }
    else {
       print_log("WARNING $this_device is not an MH object");
    }
}

Home grown detectors, e.g. PIR Motion detectors

By default Tasmota only sends on and off commands when switches change state, so if you connect a PIR to a Tasmota device, it will just send on and off whereas you probably want it to send motion and still. This Tasmota rule overcomes the problem and is a good example of a very simple Tasmota Rule.

Rule1 
on Switch1#state=1 do 
   Backlog LedPower1 1; 
   Publish stat/%topic%/PIR1 motion
endon 
on Switch1#state=0 do 
   Backlog LedPower1 0; 
   Publish stat/%topic%/PIR1 still 
endon
Rule1 1

This page has a more advanced rule that uses a timer to makes sure the motion command isn't sent too often.

Other Sensors

Tasmota has a huge number of drivers for different sensors (e.g. 1-wire temperature), however they usually publish status changes via a tele/... topic rather than a stat/... one.

Unfortunately the current Misterhouse MQTT implementation can only subscribe to one topic at a time.
Assuming you have mqtt_topic=stat/# there are 3 solutions to this.

  1. Change your mh.ini mqtt_topic to # e.g. mqtt_topic=# and edit ./lib/mqtt.pm as follows;
    Find the line with $$self{topic} = "$topic" || "home/ha/#"; and replace this with
    $$self{topic} = "$topic" || "#";. MH will then subscribe to all topics, this doesn't seem to increase CPU use significantly even with a large number of MQTT messages.
  2. Use a Tasmota rule to publish stat/... instead of tele/...
  3. Have a separate MQTT listener daemon that listens for tele/... topics and re-publishes them as stat/....

Many of the sensors report status as a JSON encoded payload, e.g. the 1-wire temperature interface reports {"Time":"2020-12-15T13:49:58","DS18S20-1":{"Id":"0008019F33E0","Temperature":16.7},"DS18B20-2":{"Id":"000001888F60","Temperature":22.6},"DS18B20-3":{"Id":"0000026B7E32","Temperature":18.5},"DS18B20-4":{"Id":"0000026B9275","Temperature":13.1},"DS18B20-5":{"Id":"0000026BA8B6","Temperature":9.3},"DS18B20-6":{"Id":"0000026BAECC","Temperature":18.7},"TempUnit":"C"} so you will need to use json_decode to get at the values.

Crafting your own MQTT clients

The Misterhouse implementation uses the perl modules IO::Socket::INET, Net::MQTT::Constants and Net::MQTT::Message;. When crafting your own clients, not surprisingly, Net::MQTT::Simple is much simpler, especially for subscribing to multiple topics.

MQTT Wildcards

When a client subscribes to a topic, it can subscribe to the exact topic of a published message or it can use wildcards to subscribe to multiple topics simultaneously. A wildcard can only be used to subscribe to topics, not to publish a message. There are two types of wildcard, a single-level wildcard e.g. tele/+/LWT or a multi-level wildcard e.g. stat/#. This is how to implement wildcards in Misterhouse;
Add your wildcard entry as a normal MQTT device e.g. MQTT_DEVICE, MQTT_test_wildcard, , mqtt_1, tele/+/LWT making sure your mqtt_topic in you mh.ini includes the topic you want to monitor e.g. mqtt_topic=#
Next you need to make sure that ./lib/mqtt.pm contains the changes introduced in the master branch in December 2020, check the subroutine parse_data_to_obj contains references to wildcards.

Finally create a state change handler for your wildcard object e.g.

if ( $state = state_now $MQTT_test_wildcard ) {
	print_log("mqtt wildcard device changed to $state by " . $MQTT_test_wildcard->{set_by_topic},"DEBUG","test_mqtt_wildcard");
}

Last Will and Testament (LWT)

MQTT Last will and testament is an extremely useful feature for detecting when devices go bad.
By default Tasmota devices set their LWT with a topic of tele/devicename/LWT and a payload of offline when they connect to the broker, and send a message of tele/devicename/LWT and a payload of online as soon as they start.
MQTT devices continually ping the broker with a keep alive message, if the broker doesn't get these messages it publishes the LWT message, so if you want to know if your device has gone bad, all you need to do is to subscribe to the LWT topic and wait.
If you want to have your Misterhouse send its own LWT messages, then do the following;

Firstly add the topic and payload to your mh.ini e.g.

mqtt_LWT_topic=tele/Misterhouse/LWT
mqtt_LWT_payload=offine

Next check /lib/mqtt.pm contains the changes introduced into Master branch in December 2020, look for MQTT_CONNECT and check it has the 2 extra parameters will_topic => $::config_parms{mqtt_LWT_topic} and will_message => $::config_parms{mqtt_LWT_payload}.

Next you need to transmit the online message as soon as it starts e.g. place the following code in you initilisation scripts

print_log( "sending LWT online message topic="
    . $config_parms{mqtt_LWT_topic}
    . " payload="
    . "online" );
$mqtt_1->pub_msg(
    message_type => MQTT_PUBLISH,
    retain       => 1,
    topic        => $config_parms{mqtt_LWT_topic},
    message      => "online"
);

To handle LWT messages sent by your other devices, simply add the wildcard device as described above and in the handler use the {set_by_topic} field to identify which device failed or recovered.

The hybrid MQTT and HTML solution

This section describes how to use HTML for control and MQTT to detect if a Tasmota device is available.

Use MQTT to detect when a device goes offline

Have a MisterHouse item looking at wildcard LWT messages e.g. in items.mht

MQTT_DEVICE, MQTT_LWT, , mqtt_1, tele/+/LWT

If this detects that a device goes offline i.e. it gets a tele/devicename/LWT topic with payload offline and the {set_by_topic} field which identifies the name of the device which failed e.g. tele/Kitchen_lamp/LWT.

A state_now handler uses these to set $devicename->{active} = 0 when the device goes offline or $devicename->{active} = 1 when it gets the online message. We can then use this later to decide if a device is contactable or not. For example;

if ( $state = state_now $MQTT_LWT ) {
	my $new_state         = $state;
	my @mqtt_message_bits = split( /\//, $MQTT_LWT->{set_by_topic} );
	my $this_device       = $mqtt_message_bits[1];
	handle_mqtt_LWT( $this_device, $new_state );
}
sub handle_mqtt_LWT {
	my ( $this_device, $LWT_state ) = @_;
        my $this_object = get_object_by_name($this_device);
	if ( !defined( $this_object->{object_name} ) ) {
		print_log(
			"handle_mqtt_LWT: MH object $this_device with state=$LWT_state does not exist",
			"WARNING", "handle_mqtt_LWT"
		);
		return;
	}
	if ( lc($LWT_state) eq "online" ) {
             $this_object->{active} = 1;
        } else {
             $this_object->{active} = 0;
        }
        return;
}

Enable MisterHouse to recognise when a device is inactive

This section makes changes to Tasmota_HTTP_items.pm so that if $devicename->{active} == 0, we know the device is offline, so there is no point in trying to contact if and run the risk of a pause while it waits for http to time out.

edit Tasmota_HTTP_items.pm to add this just at the start of the set routine;

if ($self->{active} != 1) {
        &main::print_log(substr($self->{object_name},1) .
            " is offline (" . $self->{active} . ")","DEBUG","Tasmota_HTTP");
        return;
    }

and in the http handle error section

     $self->{active} = 1;
     # Log request failures
     if ( !$response->is_success ) {
         &main::print_log("Received HTTP response code $self->{last_http_status}",
             "WARNING","Tasmota_HTTP" );
         $self->{active} = 0;
     }

Consequently it doesn't even try to send the message if it knows the device is offline.

Belt and braces

For belt and braces, have a process_item that runs every few minutes and goes through each of the Tasmotas and checks if their status (ON/OFF/not active) match the MisterHouse {state} and {active}, if the device responds at all it sets $device->{active} = 1.

Being out of the main MisterHouse loop, it doesn't matter if it takes some time over these checks.

Useful MQTT utilities

The Tasmota web Console is extremely useful for finding out whats going on with a device, simply point your browser at http://device_ip_addres/cs.

The following tools are also handy;

Activity Tool
Flashing devices via USB/FTDI Tazmotizer
Managing multiple tasmota devices TDM
Monitoring MQTT traffic MQTT.fx

Other Implementations

Acknowledgements

Thanks to;
Dave Neudoerffer for spotting the subscribe to all topics
Neil Cherry for creating the Misterhouse MQTT interface
Jeff Siddall for his work on the HTML interface and dealing with Git
Theo Arends for starting the Tasmota project
Andy Stanford-Clark and Arlen Nipper for creating MQTT.

Clone this wiki locally