meshtastic-mqtt icon indicating copy to clipboard operation
meshtastic-mqtt copied to clipboard

Detailed instructions for Home Assistant

Open Nibb31 opened this issue 3 years ago • 52 comments

Hi, Could you give some more precise instructions on how to use this with Home Assistant (and AppDaemon). Do all the scripts need to be in AppDaemon or only the main meshtastic-mqtt.py? What to put in apps.yaml? What exactly does "on appdaemon remove the argument here" mean ? How do you get a device/entities that you can interact with in Home Assistant ?

Nibb31 avatar Feb 18 '22 12:02 Nibb31

All Ive been using app daemon for is a place to leave this script running. It doesn't actually interact with home assistant at all. I'd love to make a proper integration for home assistant sometime, that would probably use this script as a major component

Here's what my apps folder looks like. This repo has diverged from the script I've got in there at the moment, I might have a look to see if there's a way to run a script from pip in home assistant somehow.

Screen Shot 2022-02-19 at 6 51 04 AM

joshpirihi avatar Feb 18 '22 17:02 joshpirihi

Hi, I put this files in appdaemon but how can runit ?

gfzmake avatar Feb 18 '22 18:02 gfzmake

Edit the meshtastic_mqtt.py script, and import the hassapi stuff and change the class definition:

#uncomment for AppDaemon
import hassapi as hass

#swap for AppDaemon
class MeshtasticMQTT(hass.Hass=None):
#class MeshtasticMQTT():

Then down the bottom comment out this bit:

#in appdaemon comment this block out
#if __name__ == '__main__':
#    main()

Finally, restart AppDaemon and watch the Log tab as it starts up, you should eventually see a message saying meshtastic-mqtt has started:

2022-02-18 19:52:38.561113 INFO AppDaemon: Initializing app meshtastic-mqtt using class MeshtasticMQTT from module meshtastic-mqtt

joshpirihi avatar Feb 18 '22 18:02 joshpirihi

image Looks promising I have to do something else ?

gfzmake avatar Feb 18 '22 19:02 gfzmake

EDIT THIS IS WRONG... SE BELOW

Oops yea you need to add this to apps.yaml:

meshtastic-mqtt:
  module: "meshtastic-mqtt"
  class: MeshtasticMQTT

joshpirihi avatar Feb 18 '22 20:02 joshpirihi

image

gfzmake avatar Feb 18 '22 21:02 gfzmake

I got that wrong. Sorry the version mismatch has me behind a little. Your apps.yaml should be

meshtastic_mqtt:
  module: "meshtastic_mqtt"
  class: MeshtasticMQTT

joshpirihi avatar Feb 18 '22 21:02 joshpirihi

image image image

gfzmake avatar Feb 18 '22 21:02 gfzmake

Getting there! Remove the =None so the class definition looks like class MeshtasticMQTT(hass.Hass):

joshpirihi avatar Feb 18 '22 21:02 joshpirihi

Aright... image image image

gfzmake avatar Feb 18 '22 21:02 gfzmake

Ok I really need to do some work here I guess. Below is my entire script that is running on my AppDaemon. It's a bit different to what is in this repo but it is working on my one:

# python3.6

from portnums_pb2 import ENVIRONMENTAL_MEASUREMENT_APP, POSITION_APP
import random
import json

import mesh_pb2 as mesh_pb2
import mqtt_pb2 as mqtt_pb2
import environmental_measurement_pb2

from paho.mqtt import client as mqtt_client

import requests

import hassapi as hass

class MeshtasticMQTT(hass.Hass):

    broker = '10.147.253.250'
    port = 1883
    topic = "msh/1/c/#"
    # generate client ID with pub prefix randomly
    client_id = f'python-mqtt-{random.randint(0, 100)}'
    # username = 'emqx'
    # password = 'public'

    traccarHost = '10.147.253.250'


    def connect_mqtt(self) -> mqtt_client:
        def on_connect(client, userdata, flags, rc):
            if rc == 0:
                print("Connected to MQTT Broker!")
            else:
                print("Failed to connect, return code %d\n", rc)

        client = mqtt_client.Client(self.client_id)
        client.username_pw_set("user", "pass")
        client.on_connect = on_connect
        client.connect(self.broker, self.port)
        return client


    def subscribe(self, client: mqtt_client):
        def on_message(client, userdata, msg):
            #print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
            se = mqtt_pb2.ServiceEnvelope()
            se.ParseFromString(msg.payload)
            
            print(se)
            mp = se.packet
            if mp.decoded.portnum == POSITION_APP:
                pos = mesh_pb2.Position()
                pos.ParseFromString(mp.decoded.payload)
                print(getattr(mp, "from"))
                print(pos)
                owntracks_payload = {
                    "_type": "location",
                    "lat": pos.latitude_i * 1e-7,
                    "lon": pos.longitude_i * 1e-7,
                    "tst": pos.time,
                    "batt": pos.battery_level,
                    "alt": pos.altitude
                }
                if owntracks_payload["lat"] != 0 and owntracks_payload["lon"] != 0:
                    #client.publish("owntracks/"+str(getattr(mp, "from"))+"/meshtastic_node", json.dumps(owntracks_payload))
                    if len(self.traccarHost) > 0:
                        traccarURL = "http://"+self.traccarHost+":5055?id="+str(getattr(mp, "from"))+"&lat="+str(pos.latitude_i * 1e-7)+"&lon="+str(pos.longitude_i * 1e-7)+"&altitude="+str(pos.altitude)+"&battery_level="+str(pos.battery_level)+"&hdop="+str(pos.PDOP)+"&accuracy="+str(pos.PDOP*0.03)
                        print(traccarURL)
                        submitted = requests.get(traccarURL)
                        print(submitted)
                #lets also publish the battery directly
                if pos.battery_level > 0:
                    client.publish("/mesh/"+str(getattr(mp, "from"))+"/battery", pos.battery_level)
            elif mp.decoded.portnum == ENVIRONMENTAL_MEASUREMENT_APP:
                env = environmental_measurement_pb2.EnvironmentalMeasurement()
                env.ParseFromString(mp.decoded.payload)
                print(env)
                client.publish("/mesh/"+str(getattr(mp, "from"))+"/temperature", env.temperature)
                client.publish("/mesh/"+str(getattr(mp, "from"))+"/relative_humidity", env.relative_humidity)
                
        client.subscribe(self.topic)
        client.on_message = on_message


    def run(self):
        client = self.connect_mqtt()
        self.subscribe(client)
        client.loop_forever()

    def initialize(self):
        self.run()

#if __name__ == '__main__':
#    mm = MeshtasticMQTT()
#    mm.run()

joshpirihi avatar Feb 18 '22 22:02 joshpirihi

I had to uncomment mqtt password image image image

gfzmake avatar Feb 18 '22 22:02 gfzmake

Oh yea the protobufs have changed too.. I will create a seperate repo for this and push up my current working files. Its diverged too much. Stand by...

joshpirihi avatar Feb 18 '22 22:02 joshpirihi

https://github.com/joshpirihi/meshtastic-mqtt-appdaemon

joshpirihi avatar Feb 18 '22 22:02 joshpirihi

Great work!

gfzmake avatar Feb 18 '22 22:02 gfzmake

image image Still need some tweaks

gfzmake avatar Feb 19 '22 03:02 gfzmake

That's working! You can ignore all the warnings there, it's just ignoring the protobufs as it should. If you connect a node to your mqtt you should now get some data out of it

joshpirihi avatar Feb 19 '22 06:02 joshpirihi

image Where should it appear ?

gfzmake avatar Feb 19 '22 13:02 gfzmake

it should create a meshtastic/ topic tree. What do you see on the AppDaemon Log tab now? Is the broker and username and password set properly?

I've just tweaked the main script on the repo to make the mqtt credentials a bit easier to set, they were hard coded.

joshpirihi avatar Feb 19 '22 16:02 joshpirihi

image image image In config of username and password username said "usename" image

gfzmake avatar Feb 19 '22 18:02 gfzmake

Should be fixed now

joshpirihi avatar Feb 19 '22 18:02 joshpirihi

image image

gfzmake avatar Feb 19 '22 19:02 gfzmake

Does your mqtt broker require credentials? If it doesn't, you'll need to comment out the line client.username_pw_set()

joshpirihi avatar Feb 19 '22 19:02 joshpirihi

Yes my mqtt require credentials.

gfzmake avatar Feb 19 '22 19:02 gfzmake

image Yeah, same error... image I have these packages installed

gfzmake avatar Feb 19 '22 21:02 gfzmake

What does your whole script look like? Are you defining username and password? It looks like it may be an issue with them

joshpirihi avatar Feb 20 '22 02:02 joshpirihi

This script? image image image

gfzmake avatar Feb 20 '22 03:02 gfzmake

Ohh sorry man my python is not great. Change the username_pw_set to

        client.username_pw_set(self.username, self.password)

joshpirihi avatar Feb 20 '22 05:02 joshpirihi

Success! connected to the mqtt but still not decode the message. image

gfzmake avatar Feb 20 '22 06:02 gfzmake

As packets are published by your gateway node, meshtastic-mqtt will translate them. That Log page should start showing some traffic if the mqtt is connected up properly

joshpirihi avatar Feb 20 '22 06:02 joshpirihi