How do I publish a JSON payload to a HABApp MqttItem?

How do I publish a JSON payload to a HABApp MqttItem?

I have a Daikin airconditioner fitted with a “Faikin” ESP32 unit (GitHub - revk/ESP32-Faikin: ESP32 based module to control Daikin aircon units).
This unit makes unit information and settings available through mqtt.

I have written the following simple code to try out controlling the unit via HABApp.
The specific MqttItems (commented out) work.
The “generic” MqttItem does not when I (i.e.) try to publish {‘power’: ‘on’} to it.
This post suggests that publishing an entire JSON payload is possible.

import HABApp
from HABApp.mqtt.items import MqttPairItem, MqttItem

class AircoAutomation(HABApp.Rule):
    def __init__(self):
        super().__init__()

        self.daikin_ac_info = MqttItem.get_item('state/daikinac/status')
        self.daikin_ac = MqttItem.get_create_item('setting/daikinac/')
        self.daikin_ac_power = MqttItem.get_create_item('command/daikinac/power')
        self.daikin_ac_settemp = MqttItem.get_create_item('command/daikinac/temp')
        self.daikin_ac_fanmode = MqttItem.get_create_item('command/daikinac/fan')
        self.daikin_ac_mode = MqttItem.get_create_item('command/daikinac/mode')

        self.run.soon(self.command_aircon)


    def command_aircon(self):
                    
        self.daikin_ac.publish({'power': 'off'})            
        # self.daikin_ac_power.publish('on')
        # self.daikin_ac_fanmode.publish('A')
        print (self.daikin_ac_power.value)
        print (self.daikin_ac_info.value['home'])

AircoAutomation()

I am aware that the topics names differ (‘command/daikinac/power’ vs ‘setting/daikinac’) but that is how the Faikin documentation specifies the mqtt topics for this device.
setting is used to publish settings in JSON format. The command topic to send commands to individual command topics (such as ‘power’, ‘mode’ etc).
Changing these topics does not alter the behavior (i.e. the settings do not come through to the device).

Considering the topic pairs - this seems to be a good use case for the MqttPairItem.
As for json - this looks good.
Can you check with a mqtt tool what is getting published on setting/daikinac/?

Out and off itself nothing is published on setting/daikinac/.

Basic principle in the following is that I am only sending power on and off commands.
As an mqtt tool I used mqtt-explorer.

Powering the AC via the Faikin web interface changed settings are published on state/daikinac/status as JSON.

When I power off the AC via openhab command/daikinac/power OFF is published.

When sending {'power': 'on'} to setting/daikinac as ‘RAW’ via mqtt-explorer I get an error:
{“ts”:“2025-06-29T18:19:47Z”,“description”:“Missing tag”,“prefix”:“setting”,“target”:“daikinac/”,“payload”:“{‘power’: ‘on’}”}

If I publish {“power” : “on”} as JSON to setting/daikinac I get a different error:
{"ts":"2025-06-29T18:28:22Z","description":"Password required to change settings","prefix":"setting","payload":"{\"no\":{\"x50a\":true,\"cnwired\":true,\"as\":true,\"icons\":true},\"uart\":1,\"auto\":{\"t\":21.0,\"r\":\"0.0\"},\"tx\":-48,\"rx\":-34,\"hostname\":\"daikinac\",\"factorygpio\":-21,\"blink\":[47,47,47],\"mqtt\":{\"host\":[\"xxxxx\"],\"user\":[\"openhab\"]},\"wifi\":{\"ssid\":\"xxxxx"}}"}

This puzzles me because mqtt-explorer is configured with the mosquito mqtt broker password.

Coming back to your first comment Sebastian, I understand that

self.daikin_ac = MqttItem.get_create_item('setting/daikinac')
self.daikin_ac.publish({'power': 'off'})

should be the correct way to publish a JSON payload to a mqtt item?

Because if that is the case, I should probably ask the Faikin developer what he thinks I am doing wrong.

Could there be other causes? In the mqtt config?

I use mosquito as a broker.
OpenHAB, HABApp and Faikin use the correct password.
HABApp config.yml excerpt:

subscribe:
    qos: 0   # Default QoS for subscribing
    topics:
    - '#'
    - 'state/daikinac/status'
    - 'setting/daikinac'
    - topic/with/default/qos
    - - topic/with/qos
      - 1

I’m on my development machine with separate running HABApp, not on listen-only.

That’s strange. You should definitely see something getting published in MqttExplorer when you load this rule.

This has nothing to do with the mqtt broker password. It’s the faikin device telling you that a password is required to change settings. That means your device is responding as expected.

This is the correct way.

# is a MQTT topic wildcard and at this place will match everything so you don’t need to add the other topics there. If you don’t want to subscribe to all topics of the broker than you should add the corresponding topics (with wildcards) here.


I would continue to investigate why nothing is published when you load the rule.
Only when you load the rule and something is published on setting/daikinac/ I would continue.
Are there some error messages or warnings in the HABApp log? Does it work when you publish something different?

When loading the rule with the following topics the following is published:

self.daikin_ac = MqttItem.get_create_item('setting/daikinac')

setting/daikinac {"power":"on"}

And with (with trailing forward slash)

self.daikin_ac = MqttItem.get_create_item('setting/daikinac/')

setting/daikinac/ {"power":"on"}

Both do not lead to switching on the airconditioner.

{"power":"true"} publishes {"power":"true"} , but does not result in airco switching on
{"power":True} publishes {"power":true} , but does not result in airco switching on

In addition I tried publishing with mosquito_pub:

erw@jedha:~ $ mosquitto_pub -t setting/daikinac -m "{'power':'on'}" -u openhab -P secretpasswd -d
Client cli sending CONNECT
Client cli received CONNACK (0)
Client cli sending PUBLISH (d0, q0, r0, m1, 'setting/daikinac', ... (14 bytes))
Client cli sending DISCONNECT

publishes the following in mqtt-explorer:

setting/daikinac {'power':'on'}
and
error/daikinac/setting {"ts":"2025-06-30T21:44:42Z","description":"Missing tag","prefix":"setting","target":"daikinac","payload":"{'power':'on'}"}

Yes - but now you know now that HABApp properly publishes the topics.

What happens if you publish the string '{"power": "on"}' from HABApp?

Are you sure that setting/daikinac is correct and it’s not command/daikinac/command with payload “on” and “off” (lower case)?
See docs on commands which includes a command to power on/off and docs on settings which doesn’t include anything with power


As a hint:
I would do this backwards: First find the correct topic and payload in mqtt-explorer that does what you want and only then do implement it in HABApp / openHAB. That way you are sure that the topic/payload combination is correct.

Those links are golden! Thank you very much, and my apologies that you had to be the one to point me to my own failure to find the correct documentation ( in my defense: I managed to follow a stale link to that documentation a day ago and was under the impression it had to be completed yet).

The links show that the settings/daikinac topic is for Faikin application settings, and that command/daikinac is for commands (as you would give with a remote or with the Faikin web app) such as power on/of, fan speed and a/c mode (heat, cool,dry. fan etc).

So, in short: I had the topics wrong.
Next step is to see how I can get info from the state/daikinac topic and following that if I kan instantiate a MqttPairItem with command/daikinac and state/daikinac.

Here is the Faikin authors reply to my question for clarification of the Faikin topic structure:

I’ll try and explain.

For a start, the structure of the topic is configurable, but I’ll assume you have not changed that.

The topic normally has there parts:-

  • The start is either command or setting. You do not want setting as that changes settings in the Faikin, which can be anything from wifi settings to GPIOs. Settings are usually best changed in the web interface. You want command which tells the Faikin to do something. power is not a Faikin setting.
  • The name, which I assume in your case is daikinac
  • In the case of a command, there is also the command you want, which in this case is control

So you want command/daikinac/control and a JSON payload. That payload can contain controls for the AC. power is a control. Do a JSON payload of {"power":true} would work. Note, as JSON, it is "power" not 'power' and true not 'true' or "true".

Succes!

import HABApp
from HABApp.mqtt.items import MqttPairItem, MqttItem

class AircoAutomation(HABApp.Rule):
    def __init__(self):
        super().__init__()

    
        self.daikin_ac_state = MqttItem.get_item('state/daikinac')
        self.daikin_ac = MqttItem.get_create_item('command/daikinac/control')

        self.run.soon(self.command_aircon)


    def command_aircon(self):
                    
        self.daikin_ac.publish({"power":True}) 
        print (self.daikin_ac_state.value['power'])

AircoAutomation()


  _   _    _    ____    _
 | | | |  / \  | __ )  / \   _ __  _ __
 | |_| | / _ \ |  _ \ / _ \ | '_ \| '_ \
 |  _  |/ ___ \| |_) / ___ \| |_) | |_) |
 |_| |_/_/   \_|____/_/   \_| .__/| .__/
                            |_|   |_|
                                        25.05.0
/Users/erw/.pyenv/versions/3.11.2/envs/habapp-dev/lib/python3.11/site-packages/easyconfig/yaml/from_model.py:55: PydanticDeprecatedSince211:Accessing the 'model_fields' attribute on the instance is deprecated. Instead, you should access this attribute from the model class. Deprecated in Pydantic V2.11 to be removed in V3.0.
True

So in the end it was all about using the correct topic name.

Speaking about MqttPairItems: would defining a MqttPairItem work as follows?

daikin_ac = MqttPairItem.get_create_item('state/daikinac', write_topic='command/daikinac/control')

Apparently not, I get an error:

[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR | Traceback (most recent call last):
[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR |   File "/Users/erw/.pyenv/versions/3.11.2/envs/habapp-dev/lib/python3.11/site-packages/HABApp/rule_manager/rule_file.py", line 79, in load
[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR |     self.create_rules(created_rules)
[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR |   File "/Users/erw/.pyenv/versions/3.11.2/envs/habapp-dev/lib/python3.11/site-packages/HABApp/rule_manager/rule_file.py", line 69, in create_rules
[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR |     runpy.run_path(str(self.path), run_name=str(self.path), init_globals=rule_hook.in_dict())
[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR |   File "<frozen runpy>", line 291, in run_path
[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR |   File "<frozen runpy>", line 98, in _run_module_code
[2025-07-01 22:49:56,107] [             HABApp.Rules]    ERROR |   File "<frozen runpy>", line 88, in _run_code
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR |   File "/Users/erw/Coding/habapp-dev/etc/rules/AircoAutomationTest.py", line 45, in AircoAutomationTest.py
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR |     AircoAutomation()
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR |   File "/Users/erw/Coding/habapp-dev/etc/rules/AircoAutomationTest.py", line 14, in __init__
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR |     self.daikin_ac = MqttPairItem.get_create_item('state/daikinac', write_topic='command/daikinac/control')
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR |   File "/Users/erw/.pyenv/versions/3.11.2/envs/habapp-dev/lib/python3.11/site-packages/HABApp/mqtt/items/mqtt_pair_item.py", line 48, in get_create_item
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR |     assert isinstance(item, cls), f'{cls} != {type(item)}'
[2025-07-01 22:49:56,108] [             HABApp.Rules]    ERROR | AssertionError: <class 'HABApp.mqtt.items.mqtt_pair_item.MqttPairItem'> != <class 'HABApp.mqtt.items.mqtt_item.MqttItem'>
[2025-07-01 22:49:56,108] [             HABApp.Rules]  WARNING | Failed to load /Users/erw/Coding/habapp-dev/etc/rules/AircoAutomationTest.py!

Or am I completely misunderstanding the MqttPairItem use?

You already created an MqttItem with the corresponding name (the topic).
When you now get_create a MqttPairItem there is an Error because you get a MqttItem and not a MqttPairItem.

Just restart HABApp and everything should work because then all HABApp internal items are gone.