-
Notifications
You must be signed in to change notification settings - Fork 130
Tasmota
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.
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
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
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);
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.
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
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.
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;
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.
- add an mqtt wildcard device in items.mht e.g.
MQTT_DEVICE, MQTT_switch_toggles, MQTT_device_toggles, mqtt_1, stat/+/SWITCH1T
- 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
- 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");
}
}
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.
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.
- 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. - Use a Tasmota rule to publish
stat/...
instead oftele/...
- Have a separate MQTT listener daemon that listens for
tele/...
topics and re-publishes them asstat/...
.
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.
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.
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");
}
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.
This section describes how to use HTML for control and MQTT to detect if a Tasmota device is available.
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;
}
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.
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.
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 |
- Jeff Siddalls DIY-Tasmota-touchpad-wall-switch
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.