Migrate from MQTT1

Hello,
I’m using file based items and rules with mqtt1 binding in OH 2.7
After switching to 3.1 i have no clue how i can use the mqtt things.
I already configured a mqtt broker and now i try to handle with items:

String Dyson455_Request "[%s]" {mqtt="> dyson455:455/XXXXXXX/command:command:*:default]"}

String Dyson455_Topic_Status_Current "[%s]" {mqtt="<[dyson455:455/XXXXXXX/status/current:state:default]"}

How can i use this items in OH3 ? i already tried to add channels and items but no luck till yet.

Thanks for posting a manual,
But i still don’t know how i have to parse the old string “dyson455:455/XXXXXXX/command:command:*:default”

The type of this thing is a string with JSON content

IMHO the term “command” points more to a switch type.
How did you use the item in MQTT 1? That should give you a pointer.

I Use this Item for a rule:

rule "455/<id>/status/current"
when
    Item Dyson455_Topic_Status_Current received update
then
    val String content = Dyson455_Topic_Status_Current.state.toString()
    val String msg = transform("JSONPATH", "$.msg", content)

    logWarn("DysonUpdate",msg)
    if (msg == "ENVIRONMENTAL-CURRENT-SENSOR-DATA") {
        val String tact_str = transform("JSONPATH", "$.data.tact", content)
        if (tact_str != "OFF") {
            var double tact = Float.parseFloat(tact_str)
            tact = (tact - 2731.5)/10
            postUpdate(Dyson455_Tact, tact as Number)
        }
        val String hact_str = transform("JSONPATH", "$.data.hact", content)
        if (hact_str != "OFF") {
            val int hact = Integer.parseInt(hact_str)
            postUpdate(Dyson455_Hact, hact as Number)
        }
        val int pact = Integer.parseInt(transform("JSONPATH", "$.data.pact", content))
        postUpdate(Dyson455_Pact, pact as Number)
        val String vact_str = transform("JSONPATH", "$.data.vact", content)
        if (vact_str != "INIT") {
            val int vact = Integer.parseInt(vact_str)
            postUpdate(Dyson455_Vact, vact as Number)
        }
    } else if (msg == "CURRENT-STATE") {
        val String fmod_str = transform("JSONPATH", "$.product-state.fmod", content)
        switch fmod_str {
            case "AUTO": postUpdate(Dyson455_Fmod, 2 as Number)
            case "FAN": postUpdate(Dyson455_Fmod, 1 as Number)
            case "OFF": postUpdate(Dyson455_Fmod, 0 as Number)
        }
        if (transform("JSONPATH", "$.product-state.rhtm", content) == "ON") {
            postUpdate(Dyson455_Rhtm, ON)
        } else {
            postUpdate(Dyson455_Rhtm, OFF)
        }
        val String fnsp = transform("JSONPATH", "$.product-state.fnsp", content)
        if (fnsp == "AUTO") {
            postUpdate(Dyson455_Fnsp, 11 as Number)
        } else {
            postUpdate(Dyson455_Fnsp, Integer.parseInt(fnsp) as Number)
        }
        val int qtar = Integer.parseInt(transform("JSONPATH", "$.product-state.qtar", content))
        postUpdate(Dyson455_Qtar, qtar as Number)
        if (transform("JSONPATH", "$.product-state.oson", content) == "ON") {
            postUpdate(Dyson455_Oson, ON)
        } else {
            postUpdate(Dyson455_Oson, OFF)
        }
        if (transform("JSONPATH", "$.product-state.nmod", content) == "ON") {
            postUpdate(Dyson455_Nmod, ON)
        } else {
            postUpdate(Dyson455_Nmod, OFF)
        }
        val int filf = Integer.parseInt(transform("JSONPATH", "$.product-state.filf", content))
        postUpdate(Dyson455_Filf, filf as Number)
        if (transform("JSONPATH", "$.product-state.fnst", content) == "FAN") {
            postUpdate(Dyson455_Fnst, 1)
        } else {
            postUpdate(Dyson455_Fnst, 0)
        }
        val String hmod_str = transform("JSONPATH", "$.product-state.hmod", content)
        switch hmod_str {
            case "AUTO": postUpdate(Dyson455_Hmod, 2 as Number)
            case "HEAT": postUpdate(Dyson455_Hmod, 1 as Number)
            case "OFF": postUpdate(Dyson455_Hmod, 0 as Number)
        }
        val String hmax_str = transform("JSONPATH", "$.product-state.hmax", content)
        if (hmax_str != "OFF") {
            var double hmax = Float.parseFloat(hmax_str)
            hmax = (hmax - 2731.5)/10
            postUpdate(Dyson455_Hmax, hmax as Number)
        }
        if (transform("JSONPATH", "$.product-state.hsta", content) == "HEAT") {
            postUpdate(Dyson455_Hsta, 1)
        } else {
            postUpdate(Dyson455_Hsta, 0)
        }
        if (transform("JSONPATH", "$.product-state.ffoc", content) == "ON") {
            postUpdate(Dyson455_Ffoc, ON)
        } else {
            postUpdate(Dyson455_Ffoc, OFF)
        }
    } else if (msg == "STATE-CHANGE") {
        val String fmod_str = transform("JSONPATH", "$.product-state.fmod[1]", content)
        switch fmod_str {
            case "AUTO": postUpdate(Dyson455_Fmod, 2 as Number)
            case "FAN": postUpdate(Dyson455_Fmod, 1 as Number)
            case "OFF": postUpdate(Dyson455_Fmod, 0 as Number)
        }
        if (transform("JSONPATH", "$.product-state.rhtm[1]", content) == "ON") {
            postUpdate(Dyson455_Rhtm, ON)
        } else {
            postUpdate(Dyson455_Rhtm, OFF)
        }
        val String fnsp = transform("JSONPATH", "$.product-state.fnsp[1]", content)
        if (fnsp == "AUTO") {
            postUpdate(Dyson455_Fnsp, 11 as Number)
        } else {
            postUpdate(Dyson455_Fnsp, Integer.parseInt(fnsp) as Number)
        }
        val int qtar = Integer.parseInt(transform("JSONPATH", "$.product-state.qtar[1]", content))
        postUpdate(Dyson455_Qtar, qtar as Number)
        if (transform("JSONPATH", "$.product-state.oson[1]", content) == "ON") {
            postUpdate(Dyson455_Oson, ON)
        } else {
            postUpdate(Dyson455_Oson, OFF)
        }
        if (transform("JSONPATH", "$.product-state.nmod[1]", content) == "ON") {
            postUpdate(Dyson455_Nmod, ON)
        } else {
            postUpdate(Dyson455_Nmod, OFF)
        }
        val int filf = Integer.parseInt(transform("JSONPATH", "$.product-state.filf[1]", content))
        postUpdate(Dyson455_Filf, filf as Number)
        if (transform("JSONPATH", "$.product-state.fnst[1]", content) == "FAN") {
            postUpdate(Dyson455_Fnst, 1)
        } else {
            postUpdate(Dyson455_Fnst, 0)
        }
        val String hmod_str = transform("JSONPATH", "$.product-state.hmod[1]", content)
        switch hmod_str {
            case "AUTO": postUpdate(Dyson455_Hmod, 2 as Number)
            case "HEAT": postUpdate(Dyson455_Hmod, 1 as Number)
            case "OFF": postUpdate(Dyson455_Hmod, 0 as Number)
        }
        val String hmax_str = transform("JSONPATH", "$.product-state.hmax[1]", content)
        if (hmax_str != "OFF") {
            var double hmax = Float.parseFloat(hmax_str)
            hmax = (hmax - 2731.5)/10
            postUpdate(Dyson455_Hmax, hmax as Number)
        }
        if (transform("JSONPATH", "$.product-state.hsta[1]", content) == "HEAT") {
            postUpdate(Dyson455_Hsta, 1)
        } else {
            postUpdate(Dyson455_Hsta, 0)
        }
        if (transform("JSONPATH", "$.product-state.ffoc[1]", content) == "ON") {
            postUpdate(Dyson455_Ffoc, ON)
        } else {
            postUpdate(Dyson455_Ffoc, OFF)
        }
    }
end

But that config belongs to

which sends commands out onto MQTT, and is not used in your rule that I can see.
To replace that you would probably make a string type channel with commandTopic set to your topic, and link that to your Item.
What part are you having trouble with, what have you tried?

At the moment i try to read the request from dyson. the rule file contains more rules which are using the send Command:

For example:

// msg "SET-STATE" ####################################

rule “455//command SET-STATE fmod”
when
Item Dyson455_Fmod received command
then
// Create current TimeStamp as UTC
//simpleDF.setTimeZone(TimeZone.getTimeZone(“UTC”))
val String timeStampUtc = simpleDF.format(new java.util.Date())
// Cast fmod to String representation
var String fmod = “OFF”
switch receivedCommand {
case 2: fmod = “AUTO”
case 1: fmod = “FAN”
}
// Create JSON for commanding and send it
cmdStr = startStateSetCmdStr + “”" + timeStampUtc + “Z”,"
cmdStr = cmdStr + ““mode-reason”:“LAPP”,”
cmdStr = cmdStr + ““data”:{“fmod”:”" + fmod + “”}}"
Dyson455_Request.sendCommand(cmdStr)
end

To get this stuff running (send command and current state) i have to convert the mqtt-1 binding components into the current version.
I try to create the broker bridge in items file:

// REQUESTS
// 455/<id>/command
//String Dyson455_Request              "[%s]" {mqtt=">[dyson455:455/XXXXXXX/command:command:*:default]"}
// TOPIC
// 455/<id>/status/current
//String Dyson455_Topic_Status_Current "[%s]" {mqtt="<[dyson455:455/XXXXXXX/status/current:state:default]"}


Bridge mqtt:broker:dyson455broker "Dyson Broker" [ host="192.168.22.8", port="1883", secure=false, username="xxx", password="xxx",  qos=1 ] 
{
    Thing topic Dyson455_Topic_Status_Current "Dyson455_Topic_Status_Current" {
    Channels:
        Type Text : dysonrequest "Dyson Request" [ stateTopic="455/XXXXXXX", commandTopic="status/current:state" ]
    }
}

But i have no clue how this will work because i’m not a MQTT and OH3 expert

A Bridge Thing is a Thing, not an Item, and belongs in a Things file in the things folder.

Once you’re using the correct file, you’ll need to fix up the syntax. There is no Text type channel in MQTT, but there is a string type.

Then, your original Item

was listening to topic 455/XXXXXXX/status/current, so you would want to put that in your stateTopic, not just "455/XXXXXXX"

Okay now its more clearly for me.
now i get follow error message when i want to use the items:

Binding configuration of type ‘channel’ of item ‘Dyson455_Request’ could not be parsed correctly.
org.openhab.core.model.item.BindingConfigParseException: UID must have at least 4 segments.

This are my current setup:

Things:
Bridge mqtt:broker:dyson455broker [ host=“192.168.22.8”, port=“1883”, secure=false, username=“xxxxxxx”, password=“xxxxxxx”, qos=1 ] {
Thing topic dyson455 {
Channels:
Type string : status [ stateTopic=“455/xxxxxxx/status/current” ]
Type string : request [ stateTopic=“455/xxxxxxx/command” ]

     }

}

Items:
String Dyson455_Topic_Status_Current {channel=“mqtt:dyson455:status”}

String Dyson455_Request {channel=“mqtt:dyson455:request”}

But have no clue whats wrong yet. I also tried commandTopic for request thing. But changes nothing.

It’s trying to tell you.

So you know it’s about this

and then

but mqtt:dyson455:request has only 3 segments.
Are you not looking at the examples given earlier?

Now understand what the segments does mean. it’s working after getting the correct channel. there was a :topic: in a segment without knowing.

Thanks for help!!

Of note, and I find it personally hard to diagnose, if if there’s an error where the binding is expecting typed information (on off etc). But the logging doesn’t generally point to what item is getting the issue.

Something to be aware of.