2

I am new to avahi. And I am not sure how to build a dns-like local area network where all devices can communicate over a mqtt gateway.

I am probably wrong. But it seems to me I want to have a unique name for each raspberry pi device on my network. mqtt-relay-server and mqtt-relay-client. But I don't have a main server. And I want to take the same sd card, copy it to several different Raspberry Pi's. And have them auto-connect into one heterogeneous system.

Question: If they are all called mqtt-relay, how do they not contact themselves? Or how can I get it to name them mqtt-relay1, mqtt-relay2, ... (depending on what it sees on the network)?

Answer:

  1. avahi-browse -al (where -l is domains other than its own).

  2. If the hostname exists on the network, use scripting to adjust the name in the avahi service

  3. Restart avahi-daemon

  4. Have mqtt point towards the original avahi dns name

  5. Whichever Raspberry Pi is connected first becomes the gateway!

Topology: Node-Red connects to my local mqtt service. There is a /subscribe/ (current info) and a /request/ (request current info be sent immediately) endpoint. Inside the payload, each device identifies itself (tank and temperature sensor with a unique id).

TamusJRoyce
  • 135
  • 1
  • 9

2 Answers2

3

Avahi (aka zeroconf aka Bonjour) is simply a way for mDNS capable machines to find each other by hostname.local.

MQTT is a pub/sub messaging system.

A publisher or subscriber needs to be able to find the broker (Mosquitto or HiveMQ) and using names rather than IP addresses is easier.

Run avahi-daemon and an MQTT client can use raspberrypi.local rather than 192.168.3.14 to find the broker.

Dougie
  • 5,381
  • 11
  • 22
  • 30
1

Possible solution with a better answer: https://serverfault.com/questions/615561/avahi-how-do-i-setup-multiple-servers-that-originally-have-the-same-hostname

Avahi with multiple instances on the same network will simply increment an integer at the end of the name. This exactly what I am needing and the below is sort-of trying to accomplish.

Since this is a built-in feature of this implementation and possibly the protocol itself, this satisfies exactly what I need.

Now to enumerate and loop through that list of servers, and I am good-to-go!

My idea is to check the network to see if my avahi service dns exists. If so, increment it by 1 until it doesn't exist. Then set this to run before avahi-daemon starts (or after...and if a change is needed, apply the change and restart avahi-daemon).

nano -w /etc/avahi/services/canrelay-mqtt.service

Insert the text:

<!-- Put this in /etc/avahi/services/mosquitto.service -->

<!DOCTYPE service-group SYSTEM "avahi-service.dtd"> <service-group> <name replace-wildcards="yes">Mosquitto MQTT server on %h</name> <service> <type>_canrelay._tcp</type> <port>1883</port> <txt-record>info=Publish, Publish! Read all about it! mqtt.org</txt-record> </service> </service-group>

Setup avahi-brows to look at the network and find similar mDNS domains:

sudo apt install avahi-browse
avahi-browse -apt | cut -d';' -f5 | grep _canrelay._tcp | sort | uniq
cat canrelay-mqtt.service | sed "s/<type>/;/" | sed "s@</type>@;@" | tr -d '\n' | tr -d '\r' | cut -d';' -f2

sudo /etc/avahi/setup-services.sh

So far I have this script:

#!/bin/bash

#avahi-browse -apt | cut -d';' -f5 | grep _canrelay._tcp | sort | uniq #cat canrelay-mqtt.service | sed "s/<type>/;/" | sed "s@</type>@;@" | tr -d '\n' | tr -d '\r' | cut -d';' -f2

mkdir /etc/avahi/service-scripts/

Only copy what doesn't exist - Well, once I learn how to send -pm flags when ran this way...

##find . -iname 'mqtt' -type f -exec cp -pn {} /etc/avahi/services /etc/avahi/service-scripts

Backup files if they do not already exist... Should this only migrate mqtt files? Probably...Lets do what is above.

yes n | cp -p -n /etc/avahi/services/mqtt /etc/avahi/service-scripts/

Copies them back to their original. service-scripts now drives services!

yes y | cp -f -p /etc/avahi/service-scripts/* /etc/avahi/services/

for f in "/etc/avahi/services/mqtt" do # Should this only apply to mqtt? Append "| grep mqtt"??? service=cat $f | sed &quot;s/&lt;type&gt;/;/&quot; | sed &quot;s@&lt;/type&gt;@;@&quot; | tr -d '\n' | tr -d '\r' | cut -d';' -f2

# If service can't be found, continue processing...
if [ -z &quot;$service&quot; ]
then
    continue
fi

# Check if the non-local service is already running
foundservice=`avahi-browse -apt --ignore-local | cut -d';' -f5 | grep $service | sort | uniq | head -n 1`

index=0
currentservice=&quot;$service&quot;
while [ &quot;$currentservice&quot; = &quot;$foundservice&quot; ]
do
    index=$((index+1))
    currentservice=&quot;${service}${index}&quot;
    foundservice=`avahi-browse -aplt | cut -d';' -f5 | grep $currentservice | sort | uniq | head -n 1`
done

if [ &quot;$currentservice&quot; != &quot;service&quot; ]
then
    # Appended number at the end, since the service already exists
    sed -i 's/$currentservice/$service/g' $f
fi

done

I haven't got to test this out yet. I only have one of the three Raspberry pi's up.

I also plan on having something similar with ESP32 and my Kendryte risc-v and their mDNS servers they can run (using the Arduino firmware - because it is quick for prototyping).

The protocol I am using is can bus. Which is why I chose can-relay. Though it is falling out of favor. Bluetooth mesh is a much better protocol.

Thank you @Dougie! I will keep editing this until I get it working how I need. With the first device having the main dns name. And all others being numbered and being secondary.

To get a list of IP's to try:

avahi-browse  _canrelay._tcp --resolve -tp | grep ^= | cut -d';' -f8-9 | sed 's/;/:/g' | sort

Since this won't act like a normal dns. It is more like an advertised address. Nice that it includes the port.

Now to use this command to setup MQTT! In progress...

Let's kick off only the server. This does not yet account for the server dropping off. Load balancing mqtt might be a solution? But anyway. Here it is:

mkdir /etc/mqtt/run.d
nano -w /etc/mqtt/run.d/canrelay.sh

Contents:

#!/bin/bash

while read -r line do nc -vz $line || continue ip=echo &quot;$line&quot; | cut -d' ' -f1 port=echo &quot;$line&quot; | cut -d' ' -f2

while read -r currentip do if [ "$ip" = "$currentip" ] then echo "port $port -> ip $ip" echo "port $port" > /etc/mosquitto/conf.d/canrelay.conf mosquitto -c /etc/mosquitto/conf.d/canrelay.conf && echo "Server mqtt has been established!" && exit 0 fi done <<< ifconfig | grep -oE &quot;\b([0-9]{1,3}\.){3}[0-9]{1,3}\b&quot; done <<< avahi-browse _canrelay._tcp --resolve -tp | grep ^= | cut -d';' -f8-9 | sed 's/;/ /g' | sort

while read -r line do nc -vz $line || continue ip=echo &quot;$line&quot; | cut -d' ' -f1 port=echo &quot;$line&quot; | cut -d' ' -f2

while read -r currentip do if [ "$ip" != "$currentip" ] then echo "port $port -> ip $ip" mosquitto_pub -h $ip -p $port -t can_relay -m "Publish stared" && echo "Client mqtt has been established!" && exit 0 fi done <<< ifconfig | grep -oE &quot;\b([0-9]{1,3}\.){3}[0-9]{1,3}\b&quot; done <<< avahi-browse _canrelay._tcp --resolve -tp | grep ^= | cut -d';' -f8-9 | sed 's/;/ /g' | sort

echo "Warning: Could not successfully establish a server or a client."

chmod +x canrelay.sh

TamusJRoyce
  • 135
  • 1
  • 9