Skip to content

Commit

Permalink
Merge pull request #886 from DaveNeudoerffer/MQTT_cleanup
Browse files Browse the repository at this point in the history
More cleanup of debug and logging.  Added ability to statically decla…
  • Loading branch information
hplato authored Apr 28, 2024
2 parents 4b25f57 + d926b57 commit 917f044
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 34 deletions.
25 changes: 16 additions & 9 deletions lib/mqtt.pm
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ my $msg_id = 1;
my $blocking_read_timeout = .5;

my %MQTT_Data;
my $init_global_v_cmd = 0;

# $main::Debug{mqtt} = 0;

Expand Down Expand Up @@ -1049,17 +1050,24 @@ sub get_voice_cmds {

#a bit of a kludge to pass along the voice command option, get the said value from the voice command.
my $object_name = $self->get_object_name();
my %global_voice_cmds = (
"<global> -- List all mqtt interfaces to the print log" => "&mqtt::print_interface_list()",
"<global> -- Publish current states of all local items" => "&mqtt_LocalItem::publish_current_states()",
"<global> -- Write all discovered items to <data_dir>/mqtt_discovered_items.mht.gen" => "&mqtt::write_discovered_items( '$::config_parms{data_dir}/mqtt_discovered_items.mht.gen' )",
);
my %voice_cmds = (
"List all mqtt interfaces to the print log" => "${object_name}->print_interface_list()",
"List retained topics for $command" => "${object_name}->list_retained_topics()",
"Publish discovery data for $command" => "${object_name}->publish_discovery_data()",
"Publish current states of all local items" => "mqtt_LocalItem::publish_current_states()",
"Cleanup discovery info on $command and republish" => "${object_name}->cleanup_discovery_topics()",
"Cleanup all retained topics on mqtt server $command and republish (BE CAREFUL)" => "${object_name}->cleanup_all_retained_topics()",
"Write all discovered items to <data_dir>/mqtt_discovered_items.mht.gen" => "&mqtt::write_discovered_items( '$::config_parms{data_dir}/mqtt_discovered_items.mht.gen' )",
"$command -- List retained topics" => "${object_name}->list_retained_topics()",
"$command -- Publish discovery data" => "${object_name}->publish_discovery_data()",
"$command -- Publish current states of local items" => "${object_name}->publish_current_states()",
"$command -- Cleanup discovery info and republish" => "${object_name}->cleanup_discovery_topics()",
"$command -- Cleanup all retained topics on mqtt server and republish (BE CAREFUL)" => "${object_name}->cleanup_all_retained_topics()",
# 'List [all,active,inactive] ' . $command . ' objects to the print log' => $self->get_object_name . '->print_object_list(SAID)',
# "Print $objects $command attributes to the print log" => "${object_name}->print_object_attrs(SAID)",
);
if( $init_global_v_cmd == 0 ) {
$init_global_v_cmd = 1;
%voice_cmds = (%global_voice_cmds, %voice_cmds);
}

return \%voice_cmds;
}
Expand All @@ -1070,13 +1078,12 @@ sub get_voice_cmds {
=cut

sub print_interface_list {
my ($self) = @_;
my @interfaces;

for my $inst (keys %MQTT_Data) {
push @interfaces, $MQTT_Data{$inst}{self}->{instance};
}
$self->log( "MQTT interface list: " . join( ',', @interfaces ) );
&mqtt::log( undef, "MQTT interface list: " . join( ',', @interfaces ) );
}

=item C<(get_interface_list())>
Expand Down
60 changes: 41 additions & 19 deletions lib/mqtt_discovery.pm
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,30 @@ sub new { #### mqtt_DiscoveredItem
my $self;
my $short_disc_topic;
my $mqtt_type;
my $disc_prefix;
my $disc_type;
my $node_id;
my $device_id;


my ($disc_prefix, $disc_type, $realm, $device_id) = $disc_topic =~ m|^(.*)/([^/]*)/([^/]+)/([^/]+)/config$|;
if( $disc_prefix ) {
$short_disc_topic = "$disc_type/$realm/$device_id/config";
} else {
($disc_prefix, $disc_type, $device_id) = $disc_topic =~ m|^(.*)/([^/]+)/([^/]+)/config$|;
if( !$disc_prefix ) {
$disc_obj->error( "UNRECOGNIZED DISCOVERY MESSAGE -- can't parse: $disc_topic" );
return;
if( $disc_topic =~ m|.*/.*| ) {
($disc_prefix, $disc_type, $node_id, $device_id) = $disc_topic =~ m|^(.*)/([^/]*)/([^/]+)/([^/]+)/config$|;
if( $disc_prefix ) {
$short_disc_topic = "$disc_type/$node_id/$device_id/config";
} else {
($disc_prefix, $disc_type, $device_id) = $disc_topic =~ m|^(.*)/([^/]+)/([^/]+)/config$|;
if( !$disc_prefix ) {
$disc_obj->error( "UNRECOGNIZED DISCOVERY MESSAGE -- can't parse: $disc_topic" );
return;
}
$short_disc_topic = "$disc_type/$device_id/config";
}
$short_disc_topic = "$disc_type/$device_id/config";
} elsif( $disc_topic ) {
$disc_type = $disc_topic;
$short_disc_topic = '';
} else {
$disc_obj->error( "UNRECOGNIZED DISCOVERY MESSAGE -- discovery topic not valid: $disc_topic" );
return;
}

my $disc_info;
Expand Down Expand Up @@ -117,7 +129,7 @@ sub new { #### mqtt_DiscoveredItem
}
}
if( $#listentopics < 0 ) {
$disc_obj->error( "UNRECOGNIZED DISCOVERY MESSAGE -- no topic: $disc_topic -- M:'$disc_msg" );
$disc_obj->error( "UNRECOGNIZED DISCOVERY MESSAGE -- no listen topic: M:'$disc_msg" );
return;
}

Expand All @@ -129,12 +141,14 @@ sub new { #### mqtt_DiscoveredItem
if( $obj->{is_local} ) {
$disc_obj->debug( 1, "Ignoring discovery message received for local object: " . $obj->{local_item}->get_object_name );
} else {
if( $short_disc_topic eq $obj->{disc_topic} ) {
if( !$obj->{disc_topic} ) {
# object explicitly declared
$disc_obj->debug( 1, "Discovery message received for unique_id:($unique_id) for object that was explicitly created: " . $obj->get_object_name );
} else {
$disc_obj->debug( 1, "Discovery message received for unique_id:($unique_id) for object that already exists: " . $obj->get_object_name );
# Update the discover message so that if discovered items are written out, they get the new ones
$obj->{disc_msg} = $disc_msg;
} else {
$disc_obj->error( "Discovery message received for unique_id:$unique_id, but topics don't match" );
$obj->{disc_topic} = $short_disc_topic;
}
}
$found = 1;
Expand All @@ -146,9 +160,13 @@ sub new { #### mqtt_DiscoveredItem
$attr = 'object_id';
}
if( $obj->{disc_info}->{$attr} eq $disc_info->{$attr} ) {
# Note that Home Assistant matches discovery objects up based on friendly name -- report error on duplicate friendly names
$disc_obj->error( "Discovery message received for friendly_name ($disc_info->{$attr}) that already exists" );
$found = 1;
if( $obj->{discoverable} || $obj->{mqtt_dynamic} ) {
# Note that Home Assistant matches discovery objects up based on friendly name -- report error on duplicate friendly names
$disc_obj->error( "Discovery message received for friendly_name ($disc_info->{$attr}) that already exists" );
} else {
$disc_obj->debug( 1, "Discovery message received for friendly_name ($disc_info->{$attr}) that has already been locally declared -- ignoring" );
}
}
}
}
Expand All @@ -158,9 +176,9 @@ sub new { #### mqtt_DiscoveredItem

# create local MH object
$obj_name = 'mqttd_';
if( $realm ) {
# $realm helps to identify the device
$obj_name .= "${realm}_";
if( $node_id ) {
# $node_id helps to identify the device
$obj_name .= "${node_id}_";
}
if( $disc_info->{name} ) {
$obj_name .= $disc_info->{name};
Expand Down Expand Up @@ -188,7 +206,11 @@ sub new { #### mqtt_DiscoveredItem
$self->{disc_prefix} = $disc_prefix;
$self->{disc_msg} = $disc_msg;
$self->{disc_obj} = $disc_obj;
$self->{discovered} = 1;
if( $short_disc_topic ) {
$self->{discovered} = 1;
} else {
$self->{discovered} = 0;
}

$self->debug( 1, "New mqtt_DiscoveredItem( \$$disc_obj->{mqtt_name}, '$name', '$disc_topic', '$disc_msg' )" );

Expand Down
34 changes: 28 additions & 6 deletions lib/mqtt_items.pm
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ Description:
mqtt_InstMqttItem
- implements a statically defined mh item for Insteon devices managed
by insteon-mqtt
by insteon-mqtt OR another instance of MisterHouse (since the MH published
MQTT messages are based on insteon-mqtt). You could also use discovered items
for this purpose.
- see https://github.com/TD22057/insteon-mqtt
- can publish HA discovery info, as insteon-mqtt does not implement discovery yet
Expand Down Expand Up @@ -152,6 +154,12 @@ Description:
- I have implemented these devices based on HomeAssistant documentation
for discovery and information on blakaddr.com
- In order to implement this properly, we would need a templating engine in perl
You can move one of the items from the file written out by write_discovered_items, or
you could hand code an item of this type using a full discovery message. When you are
hand declaring an mqtt item using this format, change the discovery_topic to just
the discovery_type -- that will internally mark it so that it is not written out
next time write_discovered_items is called.
mqtt_Discovery:
This class has 2 functions. The discovery_action parameter defines which ones
Expand Down Expand Up @@ -196,6 +204,7 @@ Usage:
# MQTT_DISCOVERY, obj name, discovery prefix, broker, publish|subscribe|both (default both)
MQTT_DISCOVERY, mqtt_discovery1, homeassistant, mqtt_1, both
###################################################
# Different Item types for different types of MQTT functionality
#
Expand All @@ -204,21 +213,26 @@ Usage:
# - It helps identify your own discovery messages in a large mqtt system
###################################################
# Used to define mqtt items as published by insteon-mqtt project
# Used to define mqtt items as published by insteon-mqtt project or as published
# by another instance of MisterHouse which has defined MQTT_LOCALITEMs.
#
# MQTT_INSTMQTT, name, groups, broker, type, topicpattern, discoverable Friendly Name
MQTT_INSTMQTT, bootroom_switch, Lights, mqtt_1, switch, insteon/bootroom/+, 1, Bootroom Light
# Define a Tasmota item. Note that the topicpattern must be in the order that the device will
# send. This is configured in the Tasmota MQTT configuration.
#
# MQTT_REMOTEITEM, name, groups, broker, type, topicpattern, discoverable Friendly Name
MQTT_REMOTEITEM, tas_outdoor_plug, , mqtt_1, switch, tasmota_outdoor_plug/+/+, 0, Tasmota Outdoor Plug
# Say you have a local INSTEON item (could be any kind of misterhouse item)
INSTEON_SWITCHLINC, 52.9E.DD, shed_light, Lights|Outside
#
# Then you can create an mqtt item to publish its state and receive mqtt commands
# Then you can create an mqtt item to publish its state and receive mqtt commands.
# TopicPattern should be of the form "<node_id>/<mqtt name>/+".
# *** This can be used to publish local MH items to Home Assistant.
#
# MQTT_LOCALITEM, name, local item, broker, type, topicpattern, discoverable Friendly Name
MQTT_LOCALITEM, bootroom_switch, shed_light, mqtt_1, switch, insteon/bootroom/+, 1, Bootroom Light
#
Expand All @@ -227,9 +241,17 @@ Usage:
.mht generated file:
# Discovery items are generated by the write_discovered_items function
# You would not normally code these by hand
# MQTT_DISCOVEREDITEM, name, discovery_obj, discovery_topic, discovery_message
# Discovery items are generated by the write_discovered_items function.
# You would not normally code these by hand.
#
# But if you want to move an item to your regular .mht file, change the discovery_topic to just
# the discovery_type. That then will override any discovered item with the same unique_id,
# and will not be written out with write_discovered_items.
#
# You could code one of these items by hand. This would also allow you to declare a remote
# mqtt item using the full discovery message format.
#
# MQTT_DISCOVEREDITEM, name, discovery_obj, discovery_topic/discovery_type, discovery_message
MQTT_DISCOVEREDITEM, mqtt_tasmota_outdoor_plug, mqtt_discovery, homeassistant/switch/877407_RL_1/config, {"name":"Tasmota Outside Plug","cmd_t":"~cmnd/POWER","stat_t":"~tele/STATE","val_tpl":"{{value_json.POWER}}","pl_off":"OFF","pl_on":"ON","avty_t":"~tele/LWT","pl_avail":"Online","pl_not_avail":"Offline","uniq_id":"877407_RL_1","device":{"identifiers":["877407"],"connections":[["mac","D8:F1:5B:87:74:07"]]},"~":"tasmota_outdoor_plug/"}
Expand Down

0 comments on commit 917f044

Please sign in to comment.