Replacing MQTT and python Logic with Home Assistant

Baba @oluwasegun74,

Well I will try to break it down. First let me outline what I think I understand your setup is. You have a bunch of Arduino(s) around your home, which you use to sense button presses, and once pressed publishes to a broker. Your broker is running on a system (Linux or Windows) which has some python scripts that do some stuffs, and send the data back to the Arduino. Like the same Ardunio used to sense the button will activate relay in the same room? Also can you explain what exactly your python scripts do and your need to

Once understood, it will be easier for one to point you in the right direction.

Regards

I believe you would be able to use templating and use only one automation, but I am not an expert in this area as I use appdaemon for all my automations. You only need one class using appdaemon, but that is a whole other topic.

It is the data part of the MQTT message - in contrast to the topic such as switch/light/topic

Bros @Odianosen25,

You are some how correct, you know that is the closest we can get to hue lights in our environment.

My broker is running on Linux as per pi level and there I’m also now wanting to include generator control and some other things.

But first let me understand the basics before I start to move to the next level because in the world of Naija na gsm/sms be our internet so that one na another talk.

This thing is very frustrating and the documentation is not helping at all, it just jumping from one thing to another. I’ve only used template when I was rendering some html but right now this is a different ball. In python script I would have imported the dictionary and then pass the dictionary in as variable to the template right now I don’t know how to import this in HA. However I have done somethings.

This is what I have done to my configuration.yaml file

sensor:

  • platform: mqtt
    state_topic: “#”

mqtt:
broker: localhost
port: 1883

This is what I see when a button press publish

This is showing the hostname_of_arduino/ip_address/button pressed i don’t know what do do again after this.

I know that I should put this in automation.yaml and this would be my trigger.payload but then I still don’t know what to do after that.

Normally what I would have done in my script is extract the button press originating hostname and the port (which is what is in my trigger.payload) use this values to lookup in the dictionary to get the switching arduino hostname and the switching port to be toggled and publish this message as the switching message, please how can i achieve this?

Is it possible for me to call a python script from the Trigger, Condition, or Action?

If not how can you direct me?

Thanks

This looks like good progress. The sensor seems to be working fine.

I think next you need to define your MQTT Light component, so that you have something to turn on. It needs to have a command_topic set to what you use to turn the light on.

You should then be able turn the light on and off from the gui.

The action of your automation would then be light.turn_on, which will send the mqtt command to the light.

I think you may be able to do what you would like to do with tables using the Python Scripts component, but again I have never used it as I use appdaemon, which has a different approach.

But you should probably do a simple yaml automation first, if only to convince yourself that you never want to do another one. :wink:

What I read about the appdeamon is that it’s supposed to work in conjunction with this, I getting already frustrated it’s taking over 96hrs of effort and for me that’s too much time. However in the last 24 to 48 hrs you have giving some courage to move on thanks for this will try to make sense of what you just said and get back with any issues

I have the table below,

title = {button_arduino_hostname, button_port, topic, switch-arduino_hostname, switch_port}

data = {
[Arduino-east, 3, home/living-room/switch/state, Arduino-Switch-Center, 20],
[Arduino-west, 3, home/kitchen/switch/state, Arduino-Switch-lower, 20],
.,

[Arduino-347gd, 12, home/security/lights/state, Arduino-Switch-lower, 46],
}

Imagine I press the button 3 on Arduino east , it is going to publish

mos_pub -h <mqtt_ip> -p <mqtt_port> -t Arduino-east/button -m Arduino-east/<its_ip_address>/3

HA is subscribe to all messages so it gets this message.

How do i get HA to call a script or appdaemon?

it’s function is to import the table and split the message with “/” as separator such that I have

variable[0] = Arduino-east
variable[1] = ip_address_of_arduino
variable[2] = 3 (which is the button pressed)

then script looks through the table for where data[0] = variable[0] and data[1] = variable[2],

Then script will publish a new mqtt_command with this details

mos_pub -h <mqtt_ip> -p <mqtt_port> -t data[3] (Arduino-Switch-Center) -m data[2] (home/security/lights/state) :::data[4] (20) ::: toggle

if you analyse the message been sent (home/security/lights/state:::20:::toggle) it is the light_switch state_topic the port where the light is connected to on the arduino and the command toggle.

so splitting the message with “(:::)” it will have
msg[0] = home/security/lights/state
msg[1] = 20
msg[2] = toggle

So the Ardino_swtich_center that is waiting for this command immediately toggles port 20 and will now publish its result

mos_pub -h <mqtt_ip> -p <mqtt_port> -t msg[0] (home/security/lights/state) -m ON or OFF (1/0) which is the present state

Now for UI control, in it’s case it will send state_topic as the variable which is (home/security/lights) to the script and in that case the script or if it’s appdaemon will

check for variable IN data[2] to get the corresponding data[2], data[3] and data[4] then it will now repeat the case of publishing once again

mos_pub -h <mqtt_ip> -p <mqtt_port> -t data[3] (Arduino-Switch-Center) -m data[2] (home/security/lights/state) :::data[4] (20) ::: toggle

And the process continues I mean this is so straight forward I don’t know if it’s clear the documentation is not clear at all.

You still seem to be trying to use HA as a python programming environment. Let me translate this into HA concepts for you.

Imagine I press the button 3 on Arduino east , it is going to publish

mos_pub -h <mqtt_ip> -p <mqtt_port> -t Arduino-east/button -m Arduino-east/<its_ip_address>/3

This a sensor, and let us call it button_3. This will be defined in ha as

sensor:
  - platform: mqtt
    name: button_3
    state_topic: Arduino-east/button

Whenenver HA receives a message with that topic, its state will be set to the payload of the message, and any automations triggered by the state change will be run. The automation (either with appdaemon, yaml or a python script) is where you will need to decode the payload (from the state) and decide which light to control. It will do this by calling the HA service (light.turn_on, light.turn_off, light.toggle)

So the Ardino_swtich_center that is waiting for this command immediately toggles port 20 and will now publish its result

mos_pub -h <mqtt_ip> -p <mqtt_port> -t data[3] (Arduino-Switch-Center) -m data[2]

This in HA terms is an mqtt light. It needs to be defined as

light:
  - platform: mqtt
    name: light_3
    command_topic: home/security/lights/state:::20
    state_topic: home/security_lights_state
    payload_on: ON
    paylaod_off: OFF

I’m afraid HA cannot handle having the command in the topic, so you will need to change that if you want to use HA. It is a very unusual way of using MQTT - the topic normally defines a target and the payload defines the operation.

Using the toggle on the gui or the HA light.turn_on service will send an MQTT message with the command_topic and payload ON, which will turn the light on.

Obviously, there is a one-one relationshitp between physical lights, and mqtt lights, so you will need to define an mqtt light component for each physical light you have.

On the sensor side, you have a separate sensor for each topic you receive, so its simpler to define a separate topic for each button, although you can decode more within the automation if necessary.

Hello,

Now we are making a headway,

Arduino-east is a trigger point it does not know the state of the light it’s so bad it does not know the light that the pressed button is controlling, because the intelligence lies with HA, so in the payload of the message from arduino-east there is no state so what you’ll be having as payload is the address of the button that was pressed which is Arduino-east/<its_ip_address>/3

How will HA now treat the information from the arduino-east every time as a state change to always trigger the Automation process meeting the condition below?

This is the begin question then we will move to the next after this.

I’m not sure this is the question you are asking, but HA will simply run all automations that are triggered when the state is changed. It is up to the code of the automation what to do with the information.

How can I relate automation process to state topic?

Thanks

There’s literally an example of an MQTT automation

Thanks so much for your support the switching part works and this is what I have for my configuration

light:

  • platform: mqtt
    name: “Living Room Lights”
    command_topic: “Arduino-Switch-Center:::home/security_lights_state:::20”
    state_topic: “home/security_lights_state”
    payload_on: “ON”
    payload_off: “OFF”

Right now from the UI it is possible to switch on a light, so the basics of what is required to switch ON and OFF Items are now clear and what is expected on my Arduino sketch to control switching is now understood I will now move to the external trigger.

Please where can I get a good explanation of appdaemon?

Thanks

Hello,

Thanks for all your help.

I think I might like appdaemon better it gives me the flexibility of been able to perform some complex tasks better and easier.

Please can you kindly show me how to pass the payload and title of MQTT sensor trigger to an appdaemon so that I perform a lookup in a dictionary and then publish another from within the appdaemon.

Try
https://home-assistant.io/docs/ecosystem/appdaemon/

and
http://appdaemon.readthedocs.io/en/stable/

This is an excerpt of an app I have for decoding 433Mhz remote buttons

$ cat Four33MHz.py 


import appdaemon.appapi  as appapi

#
# App to set items on and off if corresponding 433MHz RF control received

class four33MHz(appapi.LoggedApp):

    def initialize(self):
        self.log("initialize", level="DEBUG")
        self.listen_state(self.remote2_buttonC,
                "sensor.received_433mhz", new="13071009")
        self.listen_state(self.remote2_buttonD,
                "sensor.received_433mhz", new="13071010")
        # Other states listened for here


    def remote2_buttonC(self, entity, attribute, old, new, kwargs):
        self.log("remote2_buttonC", level="DEBUG")
        self.turn_on("switch.computer_peripherals")

    def remote2_buttonD(self, entity, attribute, old, new, kwargs):
        self.log("remote2_buttonD", level="DEBUG")
        self.turn_off("switch.computer_peripherals")
        self.turn_off("group.office_lights")
# Other callbacks here

Obviously, you would set the new= to the payload of your mqtt message (which by now is the sensor state), and the callback would contain whatever logic you would like to decide which light to turn on.

I have been doing some reading of the link that you sent to me and I have set up my appdaemon thanks, I just have some questions on the above code

The listen_state callback function is listening to entity (sensor.received_433mhz), and if the new state value it received is (13071009) then call the remote2_buttonC function, I hope I’m right with this understanding?

Is it possible to set new=(sensor.received_433mhz state value [mqtt_message])? if it’s possible kindly share the syntax to use or I should use if like you did in the below quote for another solution but in this case it will be (self.sensor.received_433MHZ) instead of (self.input_select)?

I also have an issue, I realised that if I press my external button in succession, the sensor does not record the 2nd press this I attribute to the fact that the sensor is receiving the same button address does not see it as a state change, this now clarifies why you initially advised that I treat my button press as trigger. I have learnt and thanks so very much. Just for curiosity sake if there a way to reset the sensor values after every call?

Normally if I am to create a trigger automation the procedure is you create the

a) Trigger

b) Condition (optional)

c) Action.

But now if I want to use appdaemon to handle the action, I recon I should not create ACTION so as not to create a conflict in the flow am I right with this?

In the appdaemon for this case of the trigger what callback function should I use is it listen_state or listen_event?

This is now becoming very interesting, I really look forward to hearing from you.

That is correct.

Unfortunately not directly. Someone looked at creating an event from an MQTT message a few weeks ago and came to the conclusion that you couldn’t transfer the payload. So the only way at the moment is to have the MQTT payload stored in the state of a sensor, and then trigger off the sensor state.

There is a limitation in that the state can only be 255 characters, but that doesn’t seem to be a problem here.

You can use self.listen_state for any HA component, so an input_select will work fine too.

I think receiving an MQTT message to an MQTT sensor will trigger a state change callback, even if the state is the same. But if it doesn’t, then you can always set the state of the sensor back to an unknown value at the end of your callback using self.set_state()

Correct, If you use appdaemon, you are not using yaml automations at all, so there is no need for any automations in configuration.yaml.

As above, there is no way at the moment to transfer the payload from an MQTT message to an HA Event, so the message payload will need to be stored in the state of a sensor, and you will need a self.listen_state(...) call.

Hello, thanks so very much for your response it’s giving me the courage to keep going on.

I’m so sorry if I’ve been a bother but then for me understanding the basics is key, just a comment to your observation that you raised for the other fellow, did he look at the option of reading the mqtt topic, if you remember to help my case I had to read off instructions from the cmd_topic which is the not normal way of doing things but then it worked so if he can read the topic then he should go to the source of the mqtt and concatenate the information that he wants to read off the payload with the topic and then in the appdaemon he extracts his information and discards the payload info.

Just another question if I intend to use appdaemon for the mqtt publisher in the mqtt_light component I recon that I will not specify a cmd_topic in the yaml I will just create appdaemon to listen on this and if there is a change in the state the appdaemon can then call the mqtt call service to publish the message is this right?

One key note I also need to confirm from you is from appdaemon do I have access to all my python libraries?

I was just looking back at the thread, and somebody did solve the problem of passing the payload from the MQTT message. See

You could do it this way, but I’m not sure why. It is far easier, more readable, and future proof, to say self.turn_on("light.bedroom_table") than manage the mqtt message directly in the appdaemon callback. In that way, you could have any other kind of light that HA supports as your light.bedroom_table, and your script would still work.

Just an observation for you and someone else that might be reading this thread in future I took a critical look at the call, receiving the same message does not trigger the call back, I was able to set the state with

self.set_state(entity_id, state = “”)

I felt that resetting the state might not be the best idea as this I might clear out the instruction of another button so i decided to go back to the arduino to append the time (millis) of the call to the payload though it will be discarded but then it definitely confirms a change of state.