I’m trying to create a mqtt thermostat

Hello I need Help with mqtt topics and payload for a auto discovered mqtt thermostat.
I currently have a thermostat with 4 sensors one for each room “main bedroom, sons bedroom, living room and kitchen”,
I’m stuck with my thermostat, I cant use a climate card with my current set up HA is displaying the sensors and switch separately,
I am currently working in building individual thermostats but on the mean time I’m trying to simulate one with node red and posting the topics and payloads to my mqtt broker,
so that I can create the proper mqtt topics,
at the moment my climate entity displays the current temperature and I can turn the mode between heat and off locally on the entity or remotely via node red and mqtt client,
1st issue is the rotary dial on the entity updates the mqtt broker but it wont reacts to remote updates, also wend I move it past ambient temperature nothing happens I assume I need a switch entity linked to the thermostat.
I can`t find that type of entity on the mqtt climate integration,
that’s my second issue, how do I add a switch to my thermostat?

A climate entity should have a mode select “off,heat , cool, fan” to select how you what the device should do,
and a power setting to actually “in my case” turn the heat on and off around the set point.

the mqtt integration is a bit useless in respect to mqtt topics and payloads,
it addresses HA side of the things “YAMEL” but says next to nothing about the required mqtt topic tree itself.
for example for discovery its needed a config topic in my case I am using the topic (“homeassistant/climate/LivingRoomThermostat/config”) with the following parameters

 {
    "unique_id": "LivingRoomThermostat170224",
    "name": "LivingRoomThermostat",
    "device_class": "climate",
    "modes": ["off", "heat"],
    "precision": 0.1,
    "mode_command_topic": "homeassistant/climate/LivingRoomThermostat/mode/set",
    "mode_state_topic": "homeassistant/climate/LivingRoomThermostat/status/mode",
    "temperature_command_topic": "homeassistant/climate/LivingRoomThermostat/temperature/set",
    "current_temperature_topic": "homeassistant/climate/LivingRoomThermostat/status/sensor",
    "state_topic": "homeassistant/climate/LivingRoomThermostat/status",
    "availability_topic": "homeassistant/climate/LivingRoomThermostat/status/LWT",
    "payload_available": "Online",
    "payload_not_available": "Offline",
    "power_command_topic": "homeassistant/climate/LivingRoomThermostat/power/set",
    "power_state_topic": "homeassistant/climate/LivingRoomThermostat/status/power",
    "payload_on": "ON",
    "payload_off": "OFF"
}

I need the correct mqtt topics to enable a climate switch to be auto discovered by HA on my thermostat, entity (“homeassistant/climate/LivingRoomThermostat/”).

these are the topics I created in node red so far, I can add the JSON flow if anyone is interested.

1 Like

Hi,

I’ve exactly the same problem. I’m working on code for a remote data logger, and need to dynamically create the devices in HA, using the mentioned discovery topic. I found out that I need to send two messages, one for each attribute. Below is the template I use:

{
    "temperature": {
        "device_class": "temperature",
        "state_topic": "homeassistant/sensor/##DeviceId##/state",
        "unit_of_measurement": "°C",
        "value_template": "{{ value_json.temperature}}",
        "unique_id": "temp_##DeviceId##",
        "device": {
            "identifiers": ["##DeviceId##"],
            "name": "Datalogger_##DeviceId##",
            "manufacturer": "VirtualDevice",
            "model": "PI4",
            "hw_version": "virtual_01",
            "sw_version": "2024.2.0"
        },
        "json_attributes_topic": "homeassistant/sensor/##DeviceId##/state",
        "json_attributes_template": {
            "timestamp": "{{ as_datetime(value_json.timestamp) }}",
            "humidity": "{{value_json.humidity }}",
            "battery": "{{value_json.battery }}" 
        }
    },
    "humidity": {
        "device_class": "humidity",
        "state_topic": "homeassistant/sensor/##DeviceId##/state",
        "unit_of_measurement": "%",
        "value_template": "{{ value_json.humidity}}",
        "unique_id": "hum_##DeviceId##",
        "device": {
            "identifiers": ["##DeviceId##"]
        },
        "json_attributes_topic": "homeassistant/sensor/##DeviceId##/state",
        "json_attributes_template": {
            "timestamp": "{{ as_datetime(value_json.timestamp) }}",
            "temperature": "{{value_json.temperature }}",
            "battery": "{{value_json.battery }}" 
        }        
    }
}

When i manually configure the mqtt.sensor in configuration.yaml, the data comes in, so the MQTT connection is working properly. However, when I try the dynamic configuration, it doesn’t work.

Here is the code i use when I find a new device:

def new_device_config(new_device):
    #
    # For details on the mqtt discovery see: https://www.home-assistant.io/integrations/mqtt/#sensors
    # Sensor template is defined in the config_template.json file

    # Load config templates
    with open('config_template.json', 'r') as template_file:
        templates = json.load(template_file)

    # homeassistant MQTT Integration needs one configuration topic for each "state attribute". Temple for both are defined in config_template.json
    for key, payload in templates.items():
        # Replace ##DeviceId## with actual device ID
        payload_str = json.dumps(payload).replace("##DeviceId##", new_device)
        payload = json.loads(payload_str)

        # Create MQTT topic
        config_topic = f"{mqtt_topic}/{new_device}_{key}/config"

        # Publish config message with retain flag to ensure configuration will survive HA restart
        client.publish(config_topic, json.dumps(payload), retain=True)
        print(f"Published: {json.dumps(payload)} to topic: {config_topic}")

        time.sleep(5) # sleep for 5 seconds to allow homeassitant to react, before sending next message
    #end for
    update_config(new_device)
# end def()

So this is the same problem as the OP has! Any idea? Any help will be much appreciated!

BR
Yonz

There’s next to nothing required for the topic tree. You just need to know it. Your actual sensor/thermostat can have any topic tree setup. Your discovery topic defines how HA will use those topics. The discovery topic is rigid and you have to follow the discovery documentation on how to properly create the discovery topic path.

You’re creating the same sensor twice. Your payload will not be the same for each one of those entities, yet that’s how you have it defined.

Secondly, you should post the payload you’re using and the rest of the python file. You’re doing some odd things there and I just want to make sure it’s being done correctly.

Hello Petro,

I assume that the OP as well as I did exactly that (follow the discovery documentation). Based on the documentation this is the discovery topics I’m using

config_topic = "homeassistant/sensor/XXYY3876CC05_temperature/config"
config_topic = "homeassistant/sensor/XXYY3876CC05_humidity/config"

So, the question is, why is HA not picking it up?

I’ve already replied with why it’s not. Please post the full code

Hello Petro, Sorry, I missed your second message…

This is the complete code. and the complete discovery payload. The reason I’m sending two messages is defined here MQTT-Discovery - Sensors.

Basically the two discovery topics are kept in one “config_template.json” file to make it easy to maintain. All the code does is to replace the tag “##DeviceID##” with the actual Id (Mac Address) of the discovered device

Please post the information and the full script. I can’t help without everything. Sorry.

The order of operation in your python script is wrong. You’re using declarations in your def that do not exist and are not global variables. Your python script is erroring and you aren’t seeing the errors.

After some trial and error debugging I got the script to work.

It’s worth noting that by turning on the “Debug Log” on the MQTT Integration helped a lot, as well as installing the MQTT Explorer AddOn.

So here is the Script that dynamically configures MQTT Sensors based on data read from a file. When a new device is discovered, the config_template.json is used to dynamically configure the sensor in homeassiastant

The code is on github: GitHub - yonz2/datalogger: A RPI based Datalogger

This is what the sensor looks like in HA:

Reply to OP’s question:

@sucata Sorry i hijacked your thread…

But to come back to your question, I think the issue has to do with the way you define the discovery message. (See Device Configuration Template in my Datalogger )

You need to send multiple config messages, one for each “attribute” you want to configure. In my example I send three messages (See the config_template.json in my script folder.

It’s important to watch the config Topic and how it is constructed:

homeassistant/sensor/Your_Device_ID/Your_Attribute/config

This groups all the attributes under one node (or device) in HA

Hello all, sorry for the absence,been busy at work, I wasn’t able to reply but I was reading,
and by reading this post and another HA user’s site “Resinchem Tech: MQTT 102: Add Home Assistant Discovery to your DIY Devices”, I found what was my problem, the " device" variable it’s needed for HA to be able to link the different devices into a single entity, just in case any of you need here is the final javascript code that I am using in node-red.

let msg1 = {};
let msg2 = {};
let msg3 = {};
let msg4 = {};
let msg5 = {};
let msg6 = {};


//retained topics
//config
msg1.topic = "homeassistant/climate/MainBedoomThermostat/config";
msg1.payload = {
    "action_template": "{% set values = {None:None,'idle':'idle','heat':'heating'} %}{{ values[value_json.running_state] }}",
    "action_topic": "MainBedoomThermostat/status",
    //availability
    "availability": [
        {
            "topic": "MainBedoomThermostat/status/LWT",
            "value_template": "{{ value_json.state }}"
        }
    ],
    "payload_available": "online",
    "payload_not_available": "offline",

    //identifier to join several devices together
    "device": {
        "identifiers": [
            "170224MainBedoomThermostat"
        ],
        "model": "wemos",
        "name": "D1 mini",
    },

    "unique_id": "MainBedoomThermostat170224",
    "name": "MainBedoomThermostat",
    "precision": 0.1,
    //mode
    "mode_command_topic": "MainBedoomThermostat/status/set/mode",
    "mode_state_template": "{{ value_json.mode }}",
    "mode_state_topic": "MainBedoomThermostat/status",
    "modes": [
        "off",
         "heat"
         ],

    //temperature
    "current_temperature_topic": "MainBedoomThermostat/status",
    "current_temperature_template": "{{ value_json.temperature }}",
    "max_temp": "35",
    "min_temp": "5",
    // temperature setpoint
    "temperature_command_topic": "MainBedoomThermostat/status/set/temperature_setpoint",
    "temperature_state_template": "{{ value_json.temperature_setpoint }}",
    "temperature_state_topic": "MainBedoomThermostat/status",
    "temperature_unit": "C",
    // preset
    "preset_mode_command_topic": "MainBedoomThermostat/status/set",
    "preset_mode_state_topic": "MainBedoomThermostat/status/preset",
    "preset_mode_value_template": "{{ value_json.preset }}",
    "preset_modes": [
        "manual",
        "auto",
    ]
};
msg1.retain = true;
flow.set("config",msg1);

msg3.topic = "homeassistant/number/temperature_calibration/config";
msg3.payload = {
    "availability": [
        {
            "topic": "MainBedoomThermostat/status/LWT",
            "value_template": "{{ value_json.state }}"
        }
    ],
    "command_topic": "MainBedoomThermostat/status/set/temperature_calibration",
    "device": {
        "identifiers": [
            "170224MainBedoomThermostat"
        ],
        "model": "wemos",
        "name": "D1 mini",
    },
    "device_class": "temperature",
    "entity_category": "config",
    "icon": "mdi:math-compass",
    "max": 9.9,
    "min": -9.9,
    "name": "temperature_calibration",
    "state_topic": "MainBedoomThermostat/status",
    "step": 0.1,
    "unique_id": "170224temperature_calibration",
    "unit_of_measurement": "°C",
    "value_template": "{{ value_json.temperature_calibration }}"
};

msg3.retain = true;
flow.set("temperature_calibration", msg3);

//status topic

msg4.topic = "MainBedoomThermostat/status";
msg4.payload = {
    "temperature_setpoint": 21,
    "temperature": 20.7,
    "temperature_calibration": 0,
    "mode": "heat",
    "preset": "auto",
    "running_state":"none"
};
msg4.retain = true;
flow.set("status", msg4);


//LWT topic
msg6.topic = "MainBedoomThermostat/status/LWT";
msg6.payload = {"state":"online"};
msg6.retain = true;
flow.set("LWT", msg6);

//non retained topics



return [[msg1, msg3, msg4, msg6], msg];

if any one needs help with this I’m happy to help.
thank you all.