AppDaemon + MQTT?

Thank you for offering your help.
Yes i have the mosquitto as plugin already

I have few BLE beacons and want to create a small app/server in appdeamon. I will use the happy bubbles receiver HW, but this does not send AWAY messages, just sends the beacon ID when in range
The app will listen to the beacon’s mqtt messages , will activate Home and Away for few different presence sensors based on the id and based on certain Home/Away delay (i.e. after beacon inactivity for some time will send away messages)

I know that there are room_assistant and happy bubbles server, but i have hass.io and can not install them Also it does snot make sense to buy a separate HW for that alone.

In a nutshell i want to access mqtt messages directly from appdeamon. From other reads it seems not possible.
I can try what @gpbenton suggested with another automation in hass.io to pass th emessage

May be there are easier ways?? Thank you

Like a lot of home assistant things there are a few different ways.

  1. Just have an automation that sets those sensors states based on mqtt messages directly. Unless you need a fair bit of logic to it, that would be the easiest. The logic for the delay might be tricky though and I would do it in appdaemon but it could be done.

  2. Something else I added a while back is event_data_template. So you can have an automation that looks like this

- alias: ble_mqtt
  trigger:
    platform: mqtt
    topic: mytopic/Iamlistening/to
  action:
    event: HASS_MQTT
    event_data_template:
      topic: '{{ trigger.topic }}'
      payload: '{{ trigger.payload }}'

Then in your appdaemon code:

    def initialize(self):
         self.listen_event(self.event_listener, 'HASS_MQTT')

    def event_listener(self, event_name, data, *args, **kwargs):
        self.log("__function__: %s" % data, 'INFO')
        payload = json.loads(data['payload']) if data.get('payload') else {}

        myvar = payload.get('myvar')

So you listen for the mqtt message with the automation, fire an event which you listen for in your app, and then you get the full mqtt packet as data.payload and data.topic.

3 Likes

Now that is smart! That is just what I need to tide me over until Appdaemon learns about MQTT.

Thanks!

EDIT - I am getting the error

    payload = json.loads(data['payload']) if data.get('payload') else {}
NameError: name 'json' is not defined

I am guessing I need to add an import of something - is that right?

EDIT 2 - Yup: import json :slight_smile:

Thank you!
This is where I was going towards and your pointer will be a good start.
I am getting the happy bubbles in day and let you know how it goes.

1 Like

quick update:
Got the happy bubbles and made it work.

Used the automation from @tschmidty to push the the mqtt traffic to appdeamon:
Appdemon server is below. It listens to multiple beacons and updates the tracker status (home/not home) and updates the attributes from the beacons. I am using the same UUID, and the difference in major version is an indication of different people.

Thanks for the help

	class MQTTServer(hass.Hass):

	  def initialize(self):
		self.HomeDelay = 1
		self.AwayDelay = 10
		now = self.datetime()
		self.DeviceMap = {'0001':{"topic":"presence/kd_ble","device":"device_tracker.kd_ble","heartbeat":now,"payload":""}, '0002':{"topic":"presence/joy_ble","device":"device_tracker.joy_ble","heartbeat":now,"payload":""}}
		self.listen_event(self.event_listener, 'HASS_MQTT')
		self.run_every(self.home_handler,now, self.HomeDelay)
		self.run_every(self.away_handler,now, self.AwayDelay)

	  def home_handler(self,kwargs):
		now = self.datetime()
		for device_key in  self.DeviceMap:
			tracker = self.DeviceMap[device_key]        
			if  (now - tracker['heartbeat']).total_seconds() < 2*self.HomeDelay:
				if self.get_state(tracker['device']) != "home":
					self.set_state(tracker['device'],state = "home",attributes =tracker['payload'] )


	  def away_handler(self,kwargs):
		now = self.datetime()
		for device_key in  self.DeviceMap:
			tracker = self.DeviceMap[device_key]  
			if  (now - tracker['heartbeat']).total_seconds() > self.AwayDelay:
				if self.get_state(tracker['device']) != "not_home":
					self.set_state(tracker['device'],state = 'not_home',attributes =tracker['payload'] )

	  def event_listener(self, event_name, data, *args, **kwargs):
	 #   self.log("__function__: %s" % data, 'INFO')
		payload = json.loads(data['payload']) if data.get('payload') else {}
		device_key = payload.get('major')
		if device_key in self.DeviceMap:
		   self.DeviceMap[device_key]['heartbeat'] = self.datetime()
		   payload["last_seen"] = self.DeviceMap[device_key]['heartbeat'].strftime("%Y-%m-%d %H:%M:%S")
		   self.DeviceMap[device_key]['payload'] = payload
3 Likes

this will work in a lot of cases, but not every time.
start_time (where you give now) must be a time in the future.
i have experienced some cases where i restarted an app and there was a slowdown in the system, resulting that that line trows an error because time is a time in the past (AD works with 1 second loops, if something slows down the init for 1 second it will go wrong)

so i advice to use a time 5 seconds after now.

I’ve finally been able to do some testing and I was able to get a client connection to my local mqtt broker using your plugin and client certificates. Specifically, the client certificates authenticate the connection and the user name and password are not used. (It does seem to need the user name but a password was not supplied or defined in the appdaemon.yaml file.)

To get it to work I had to add 2 lines to the mqttplugin.py file to allow the ca.cert file to be passed to the client.tls_set() method. (The first new line was to get the path to the ca.cert file from the appdaemon.yaml file.)

I also added two other lines to the mqttplugin.py file to add a client_id string. It allows the mosquitto server/broker to use the client id in its logs instead of a random string of characters that are used when a client id is not supplied.

I’ve attached a diff file for the 4 changed lines. (I had to give it a .yaml extension because this web site only allows certain file types to be uploaded.)

Thanks again for the work on the plugin.

mqttplugin.diff.yaml (713 Bytes)