Number to String

Hi All,

do you know if with OH2 there is a way to go from Number to String without a Rule?

Is Scale only a Num-Num solution?
https://docs.openhab.org/addons/transformations/scale/readme.html

thanks
Andrea

Let me clarify with an example. I know, this code is working but definitely HORRIBLE!!! Any better solution to convert a number in a more readable string?

Example: wind strength classified with Beaufort index

two items:
Number Http_Wunderground_WindBeaufort “Beaufort Index: [%s]” (gOutdoor, gWeather) {weather=“locationId=Home_WU, type=wind, property=speed, unit=beaufort”}
String Http_Wunderground_WindBeaufortIndex “Beaufort Index: [MAP(beaufort.map):%s]” (gOutdoor, gWeather)

the beaufort.map:
-=na
0=calm
1=Light Air
2=Light Breeze
3=Gentle Breeze
4=Moderate Breeze
5=Fresh Breeze
6=Strong Breeze
7=High Wind
8=Gale
9=Strong Gale
10=Storm
11=Violent Storm
12=Hurricane

and the rule:

// Wind Beaufort Rules

rule “Wind Beaufort Rating”
when
Item Http_Wunderground_WindBeaufort changed or
System started
then
// if (Http_Wunderground_WindBeaufort.state == Undefined || Http_Wunderground_WindBeaufort.state == Uninitialized)
// return false
// else {
var Number bf = Http_Wunderground_WindBeaufort.state as DecimalType
var Number w
if (bf = 12) {w = 12}
else if (bf = 11) {w = 11}
else if (bf = 10) {w = 10}
else if (bf = 9) {w = 9}
else if (bf = 8) {w = 8}
else if (bf = 7) {w = 7}
else if (bf = 6) {w = 6}
else if (bf = 5) {w = 5}
else if (bf = 4) {w = 4}
else if (bf = 3) {w = 3}
else if (bf = 2) {w = 2}
else if (bf = 1) {w = 1}
else {w = 0}
postUpdate(Http_Wunderground_WindBeaufortIndex, w)
logInfo(“rules”, “Wind Beaufort Rating completed”)
// }
end

the “if/return false” is not working for now.

Any better idea?
Thanks for your support. Any suggestion will be much appreciated.

Andrea

Hi Andrea!

I will try to help you but I must say that I do not fully understand what you are trying to achieve. I assume you have a Number item updated by a binding and want to convert that number to a String for display in a sitemap (using a transformation).

First some friendly advice concerning your code. Please use code fences for better readability. I also “refactored” your code and included some notes / hints.

rule "Wind Beaufort Rating"
when
    Item Http_Wunderground_WindBeaufort changed or
    System started
then
    if (Http_Wunderground_WindBeaufort.state == NULL) {
        // no need to return false
        return
    }
    // Use a val (constant) instead of a var (variable)
    val Number bf = Http_Wunderground_WindBeaufort.state as DecimalType
    var Number w

    /*
     * You are assigning a Number to a Number (I do not really know why)
     * which could be done by just assigning the value:
     */
    w = bf

    /*
     * But if you must convert a value by a list of known values, use the
     * switch statement instead of if-elseif-else.
     */
    // switch bf {
    //     case 2: w = 2
    //     case 1: w = 1
    //     default: w = 0
    // }

    // Use Item.postUpdate() instead of global method
    Http_Wunderground_WindBeaufortIndex.postUpdate(w)

    logInfo("rules", "Wind Beaufort Rating completed")
end

Now that that’s out of the way I will try to answer your question. Your approach should work without the need for a “dummy” String item. Just use the MAP approach with the Number item and define a Text in your sitemap displaying the Number item:

Number Http_Wunderground_WindBeaufort "Beaufort Index: [MAP(beaufort.map):%s]" (gOutdoor, gWeather) {weather=“locationId=Home_WU, type=wind, property=speed, unit=beaufort”}

And then in your sitemap:

sitemap home label="My Home" {
	Text item=Http_Wunderground_WindBeaufort
}

Which should give you (assuming Http_Wunderground_WindBeaufort.state == 0):

Beaufort Index: calm

Does that answer your question?

Thank you very much, @jewesta … your post is very informative for me.

Now it works like a charm :slight_smile:
I don’t know why the same approach was not working with OH1 (tried in the past, for sure). :face_with_raised_eyebrow:

thanks again
Andrea

I have another question, I don’t know if you can help me.

The solution above is perfect when I have a Number and I need to convert to a String

example: “1” -> Wind

But what about when I receive in the same array 2 values?

I receve “21” and it means “2” and “1”

At the moment I’ve created the entry 21 in the map file, and I say “Fog/Wind” for example, if 2 means “Fog” and 1 “Wind”.

But I’m wondering to know if there is a better way for doing that. :slight_smile:
thanks
Andrea

The problem here is that “21” is not really an array. OH will interpret that as a string containing a number.
You may want to have a look at a javascript transform

going more specific.

attached you can find an output from Wunderground Alarms about the current situation in Huesca, Spain. We have 2 alerts, so good example.

zmw_00000.210.08094.xml (3.3 KB)

items:

/*Wunderground Meteoalarm */

Number WuAlarmsCode “meteoalarm [MAP(wu_alarms_code.map):%s]” { http="<[WuAlertsCache:10000:XSLT(wu_weather_alerts_type.xsl)]" }

Number WuAlarmsLev “level [%d] { http=”<[WuAlertsCache:10000:XSLT(wu_weather_alerts_level.xsl)]" }

in http.cfg:

configuration of the first cache item: Meteoalarm every 5 mins

WuAlertsCache.url=http://api.wunderground.com/api/xxxxxxx/alerts/q/zmw:00000.210.08094.xml
WuAlertsCache.updateInterval=300000

wu_weather_alerts_type.xsl:

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”>

<xsl:output indent="yes" method="xml" encoding="UTF-8" omit-xml-declaration="yes" />

<xsl:template match="/">
	<xsl:for-each select="//response/alerts/alert">
		<xsl:value-of select="wtype_meteoalarm"/>
	</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

wu_weather_alerts_level.xsl:

<?xml version="1.0"?>

<xsl:stylesheet xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”>

<xsl:output indent="yes" method="xml" encoding="UTF-8" omit-xml-declaration="yes" />

<xsl:template match="/">
	<xsl:for-each select="//response/alerts/alert">
		<xsl:value-of select="level_meteoalarm"/>
	</xsl:for-each>
</xsl:template>

</xsl:stylesheet>

It works, but not as expected. When I have 2 alerts in facts I see:

WuAlarmsCode= “12” because first alert value is “1”, and second is “2”
WuAlarmsLev= “22”, because both alerts are in this case Level 2

Any clue how to solve this issue?

thanks
Andrea

Does the weather underground provide a json result instead of xml?
The you could access each alarm separately on two items with a slightly different JSONPATH transform for each

Yes we have :slight_smile:

http://api.wunderground.com/api/354d93b043833b5e/alerts/q/zmw:00000.210.08094.json

How can I access each alarm separately?

Then I need to create multiple items? A sort of

Alarm1/Level1
Alarm2/Level2

and they will be populated only when I’ll have multiple alarms?

Andrea

Hi Andrea,

the WU-JSON is much better for automation than the XML. Please have a look on the thread:

From your JSON in Huesca, you can see:

	"alerts": [
		{
		"type": "WND",
		"wtype_meteoalarm": "1",
		"wtype_meteoalarm_name": "Wind",
		"level_meteoalarm": "2",
		"level_meteoalarm_name": "Yellow",
...
		{
		"type": "WIN",
		"wtype_meteoalarm": "2",
		"wtype_meteoalarm_name": "Snow/Ice",
		"level_meteoalarm": "2",
		"level_meteoalarm_name": "Yellow",

you get the type and the level in distinct attributes for both alerts WND and WIN.

PS: After settling all that, you should Change your WU API Key! :wink: it’s in the URL you provided… :wink:

another Thing unrelated. If you’d like your OH2 to speak spanish on weather, have a look here:

you can add spanish language support for the alerts and weather description.

Thanks all for this clarification.

But how can, for example, populate item1 with alert1 and item2 with alert2, and so on?

I’ts always alerts.wtype_meteoalarm for both alerts, how to understand what is first and what is, in case, second/third/…?

maybe, using a brute-force approach, I can

  1. create 12 items for all 12 alarms we can have via meteoalarm

  2. find a way to say "populate item1 if wtype_meteoalarm is “1”, item2 if is “2”, … and so on.

Does it make any sense?

In your http.cfg

weatherConditions.url=the_url_for_wu_underground_json_with_your_api_key
weatherConditions.updateInterval=360000

items file:

String Alarm1 "Alarm1 [%s]" { http="[weatherConditions:360000:JSONPATH($.alerts[0].wtype_meteoalarm_name)]" }
String Alarm2 "Alarm2 [%s]" { http="[weatherConditions:360000:JSONPATH($.alerts[1].wtype_meteoalarm_name)]" }

If there is only one alarm, the Alarm2 value will be an empty string

You don’t need to, the wtype_meteoalarm_name is provided by the api!!

Yes, idea is

if there is 1 alarm, 1 Alarm will have a value
if there are 2 alarms, 2 Alarms will have a value

Then I will play with visibility in my sitemap, to see only the items with an alarm.

But I need to populate all 12 items, each with the right alarm.

Does it make any sense? any other clue?

Why do you want 12 items? Do you get 12 weather alarms in one location at any one time?

No, correct @vzorglub

with your approach $.alerts[0] (the number in brackets is the first of the array, right?) we don’t need to have more than 3-4 alerts for sure

shall I also associate the right level of alert for each item?

maybe same approach, then I concat Alarm1 + Level1 and so on?

Correct, unless you live in a place with a hell of a weather you will never have more than two or three weather alerts at any one time. [0] is the first alert, [1] is the second…

If you paste your json in jsonpath.com, you can play with the jsonpath expression to get whatever value you want and assign it with an item.

2 Likes