String type - cut a part of

  • Platform information:
    • Hardware: RAspberry 4
    • OS: Raspbian
    • Java Runtime Environment: which java platform is used and what version
    • openHAB version: 2.5
  • Issue of the topic: string manipulation

Guys, tell me how I can manipulate data read as STRING type.
MQTT sends me the value [“Time”: “2021-01-29T20: 24: 08”] and I would like to leave only the string “29T20: 24”. Is there any rule that will truncate the first 8 and last 3 characters of the sequence? I was looking for and I do not see anything similar in JSONPATH, can I write a rule somehow?

substring is the method you’re looking for. Just Google on Java substring and you’ll get many examples.

1 Like

Feel so close but not enough

rule "close"

  when

Item D1APogodaRead changed
then
// use the transformation service to retrieve the value
val newValue = D1APogodaRead.toString.substring(0,11) 
// post the new value to the  Item
NEWread.postUpdate( newValue )
end

So incoming value of D1APogodaRead is “2021-01-29T20: 24: 08” and after above substring transformation from sign 0 to 11, NEWread looks like “D1APogodaRe” instead of expected “2021-01-29T”.

It’s doing just what you asked; start at character 0 (the first character) and give you the next 11 characters.
Maybe you meant to start at 8 (the ninth character)?

The other thing you probably want to do is to substring the state of the Item, not the whole thing with names,labels, icons, etc. Go one step at a time -
item.state.toString.substring()

Rossko57 you are the best!
This .state. missed and blocked before the right result :slight_smile:

One more query:
Currently written rule converts one specific “item” into expected output.
Is it possible to process more items? Do I have to copy 50 rules for 50 items? Three examples are shown below.

08:37:09 MQT: tele / K / Hall / BME / SENSOR = {"Time": "2021-02-01T08: 37: 09", "BME280": {"Temperature": 24.7, "Humidity": 24.3 , "DewPoint": 2.9, "Pressure": 988.1}, "PressureUnit": "hPa", "TempUnit": "C"}
08:33:56 MQT: tele / K / Hall / Light / STATE = {"Time": "2021-02-01T08: 33: 56", "Uptime": "11T09: 10: 22", "UptimeSec": 983422, "Heap": 28, "SleepMode": "Dynamic", "Sleep": 50, "LoadAvg": 19, "MqttCount": 1, "POWER": "OFF", "Wifi": {... }}
08:53:44 MQT: tele / K / Hall / Dryer / SENSOR = {"Time": "2021-02-01T08: 53: 44", "ENERGY": {"TotalStartTime": "2020-12-13T16: 25:27 "," Total ": 25.004," Yesterday ": 0.007," Today ": 0.004," Period ": 0," Power ": 0," ApparentPower ": 0," ReactivePower ": 0," Factor " : 0.00, "Voltage": 241, "Current": 0.000}}

from each need to extract the “Time” part that used to get with
“transformationPattern =” JSONPATH: $. Time “”
in the channel configuration and then scrapping specific characters with substring.

So what do you think is it somehow possible? It seems to me that transformation in a common .js file should be solution, but before start exploring javascript, the most important question is, will OH3 support it after all(I plan to upgrade in 3 months)?

As you rule is secret, the answer is “probably”.
Recommended reading -

However, it seems you are extracting datetime from MQTT.
I would use transformation to get that data into a standard openHAB DateTime Item for convenience. If this is just about what you want to display, this would work better.

But if you need your original 50 string Items and want 50 just-the-time Items as well, you can create second MQTT channels that do different transformations to the same data but link to different Items.

If you tell us what you are trying to achieve it will help choose paths.

Indeed, it should be easier if I explain what I want to do and why. Perhaps there is an easier path to solve :slight_smile:

So:
I have about 45 devices with tasmota software installed at home. Each of these devices reports its condition via MQTT to the mosquito at a specified teleperiod (300seconds).
As there were times when devices lost their network and restarted, I would like to be able to see when I received the last report from a given device. Reason of my post: a check whether my devices are still online or working properly.
Each of them, as I posted above, sends report that look like this:

08:37:09 MQT: tele / K / Hall / BME / SENSOR = {"Time": "2021-02-01T08: 37: 09", "BME280": {"Temperature": 24.7, "Humidity": 24.3 , "DewPoint": 2.9, "Pressure": 988.1}, "PressureUnit": "hPa", "TempUnit": "C"}

08:33:56 MQT: tele / K / Hall / Light / STATE = {"Time": "2021-02-01T08: 33: 56", "Uptime": "11T09: 10: 22", "UptimeSec": 983422, "Heap": 28, "SleepMode": "Dynamic", "Sleep": 50, "LoadAvg": 19, "MqttCount": 1, "POWER": "OFF", "Wifi": {... }}

08:53:44 MQT: tele / K / Hall / Dryer / SENSOR = {"Time": "2021-02-01T08: 53: 44", "ENERGY": {"TotalStartTime": "2020-12-13T16: 25:27 "," Total ": 25.004," Yesterday ": 0.007," Today ": 0.004," Period ": 0," Power ": 0," ApparentPower ": 0," ReactivePower ": 0," Factor " : 0.00, "Voltage": 241, "Current": 0.000}}

I imagined that I could extract part of report “Time:” 2021-02-01T08: 37: 09 " from these reports and then extract characters from 9 to 16, which return me “01T08:37” which is the day and time along with the minutes of the last message sent.
So for one item you solved the matter by helping above. Now it works like that:

String WeatherReportA "Weather report" {channel = "mqtt: topic: d1weather: read"}

so that string has one transformation already within Things configuration:

Type string: read “Weather” [
stateTopic = “tele / K / Hall / BME / SENSOR”,
transformationPattern = “JSONPATH: $. Time”
]

so every 5 minutes I receive string “2021-02-01T08: 37: 09”
then working with rules

rule “lastmessage”
when
Item WeatherReportA changed
then
// use the transformation service to retrieve the value
val newValue = WeatherReportA.state.toString.substring (09.16)
// post the new value to the Item
NEWread.postUpdate (newValue)
end

so receive my expected value “01T08:37” at

String NEWread "TransformedDataValue"

However, following a similar way of thinking to the remaining 44 devices would mean creating another 44 rules which could make my code messy.

POSSIBLE SOLUTION:
I thought that maybe we could create a general transformation function, e.g. in the form of Transform> javascript, which I would refer to the channel in the things text file

Type string: read2 “Weather” [
stateTopic = “tele / K / Hall / BME / SENSOR”,
transformationPattern = “JS: test.js”
]

String WeatherReportA "Weather report" {channel = "mqtt: topic: d1weather: read2"}

I even started writing a function test.js but it doesn’t work as expected and only returns UNDEF.

(function (xyz) {
if (xyz! == 0) {
// here is part of Time extraction missing cause first trying to do substring extraction
var newValue = xyz.state.toString.substring (09.16);
return newValue;
}
else {
return “UNDEF”;
}
}) (input)

Man that is longest post of my life. What do you think about? (solution not post itself :slight_smile: )

OK, given this is what you are truly after, I’d recommend linking a DateTime Item to one of the other MQTT Channels (or all of them) and apply the Timestamp profile to the link. Any message received on and of those Channels will cause the DateTime Item to update to now.

No need for any rules with this approach.

This is never ever required. If you can’t figure out how to avoid this you should come here and ask. You should never have to make more than one such rule.

See Design Pattern: Associated Items for how to handle any number of such Items using one Group and one rule.

If you’ve got a fairly standard date-time coming in from Tasmota, I’d be inclined to link that to a standard openHAB Item.
You’ve got an odd-looking time format incoming, with extra spaces, but I think the standard parser will cope with that?
So you’d make a new datetime type channel with the same JSONPATH extract transform, and link to a DateTime type Item.

EDIT - Rich’s approach is valid too, of course, and probably preferable.
You have a choice of recording when the last message arrived, by openHAB’s clock. Or recording what the Tasmota thought the time was when it sent the last message.

Once you’ve got a DateTime, it’s trivial to format to “hh:mm” or whatever for display. No partner Items needed.

This JS transform would not work, it has no access to your Items, only the one string being passed in from the channel. xyz is just a string.

Thank you guys! I can not believe that solution is so simple and easy to implement :slight_smile: