Map battery level to %

openhab2
Tags: #<Tag:0x00007f1e5cbd6f88>
(Kim Skatun) #1

Most of my battery sensor uses battery level as % and this shows nicely in the sitemap, where icon shift colors depending on the level:

My items looks like this:

Number Netatmo_Bedroom_Battery "Battery status [%d/5]" (Group_Netatmo,Group_Battery){netatmo="xxxxxxxxxxx#BatteryStatus"}
Number Netatmo_MasterBedroom_Battery "Battery status [%f]" (Group_Netatmo,Group_Battery){netatmo="xxxxxxxxxxx#BatteryStatus"}

I also tried using mappings:
Number Netatmo_MasterBedroom_Battery "Battery status [%f]" (Group_Netatmo,Group_Battery){netatmo="xxxxxxxxxxx#BatteryStatus"} mappings=[1=20,2=40,3=60,4=80,5=100]

So how can I convert the number 5 to 100% so that icon shows correctly up in sitemap?

0 Likes

(Harry) #2
rule "Netatmo_Bedroom_Battery"
when
  Item Netatmo_Bedroom_Battery received command
then
  Netatmo_MasterBedroom_Battery.postUpdate((receivedCommand as DecimalType) * 20)
end
1 Like

(Joachim Boeddeker) #3

Or use a MAP tranformation

netatmobattery.map

0=0
1=20
2=40
3=60
4=80
5=100
String Netatmo_MasterBedroom_Battery "Battery status [MAP(netatmobattery.map):%s]" (Group_Netatmo,Group_Battery){netatmo="xxxxxxxxxxx#BatteryStatus"} 

Didn’t check this, maybe you need a SCALE trasnformation because of the Number. But idea is similar.

Edit: Better use @hr3’s idea, because then you have your batterie leves identically scaled. Makes it easier in rules.

0 Likes

(Kim Skatun) #4

I didn’t think about doing mapping directly on the item and convert it to string

@hr3 Nice rule, I will modify to loop over all group items to only have 1 rule instead of 3…

 rule "Netatmo Battery"

when

  Item Group_Netatmo_Battery received command

then
   val changedUnit = Group_Netatmo_Battery.members.filter[ItemChanged| ItemChanged.lastUpdate != null].sortBy[lastUpdate].last

  changedUnit.postUpdate((receivedCommand as DecimalType) * 20)

end
1 Like

(Joachim Boeddeker) #5

No. Use triggeringItem and proxyitems!

Number NetatmoBattery1_proxy "Battery1 [%f]" (Group_Battery)
Number NetatmoBattery1_proxy "Battery2 [%f]" (Group_Battery)
Number NetatmoBattery1_proxy "Battery3 [%f]" (Group_Battery)
rule "battery changed"
when
  Item NetatmoBattery1 changed or
  Item NetatmoBattery2 changed or
  Item NetatmoBattery3 changed
then
    var Number battery = Integer::parseInt(String::format("%s",triggeringItem.state.toString)) * 20
    sendCommand(triggeringItem.name + "_proxy", battery.toString)
end

Using sendCommand instead of postUpdate let’s you trigger on the change of the proxy.

0 Likes

(Kim Skatun) #6

Why can I not do like this, to avoid having proxyItems maybe @rlkoshak knows it ?

rule "battery changed"
when
     Item Group_Netatmo_Battery received command
then
    var Number battery = Integer::parseInt(String::format("%s",triggeringItem.state.toString)) * 20
    triggeringItem.postUpdate(battery.toString) // Post will not get the group to receive a new command..
end
0 Likes

(Joachim Boeddeker) #7

Sorry, you need proxy items for @hr3’s solution as well he just called it ‘Master’.

You do not want to have a rule fighting against a binding to set a value on the same item!

0 Likes

(Kim Skatun) #8

Sure its not a typo in @hr3 example? I have both MasterBedroom and Bedroom…

0 Likes

(Joachim Boeddeker) #9

Whatever. Do whatever you like, but i do not suggest doing that without proxy items :wink:

0 Likes

(Josar) #10

It will get easier with the Member of Group Trigger

But as @job said when changing transforming the value in the rule don’t set it to the same Item.
This will probably lead to conflicts, but in your case this could be an exception.

  1. The Item is only one way. Get info from node.
  2. The rule is set to received command
  3. The Item state is change by postUpdate which does not trigger the rule again.
  4. The incomming and transformed value is a number

As there is no other interaction with this Item, this could work out without issues.

0 Likes

(Rich Koshak) #11

Looks like you got the answers but I’ll reiterate.

  1. The rule will never trigger unless you explicitely send a command to Group_Netatmo_Battery. Commands send to members of Group_Netatmo_Battery only generate updates to Group_Netatmo_Battery.

  2. Even if the trigger worked, triggeringItem would be set to Group_Netatmo_Battery, not the member of the Group that caused the Rule to trigger (see the new Member of trigger in the link from Josar below)

  3. As Josar indicates, in this case you might be able to get away without using the proxy Item but it will be really easy to run into problems if you ever have any other rules that trigger on updates.

Personally, I think this is really a job for a JS transform rather than a Rule. Leave the Items as is and use

(function(i) {
    if(isNaN(i) return "NA";
    return i*20;
})(input)

Then the label becomes “Battery status [JS(battery.js):%s %]” or something like that. No proxies, no rules.

1 Like

(Kim Skatun) #12

You have a small bracket error in the js above,

(function(i) {
    if(isNaN(i)) return "NA";
    return i*20;
})(input)

However i can not get it to work properly, get the % sign to show up.

Text item=Netatmo_Outdoor_Battery label="Netatmo Bedroom Battery status [JS(netatmo_battery.js):%.0f %%]" icon="battery" 
			Text item=Netatmo_Bedroom_Battery label="Netatmo Bedroom Battery status [JS(netatmo_battery.js):%s]" icon="battery"
			Text item=Netatmo_MasterBedroom_Battery label="Netatmo Master Bedroom Battery Battery status [JS(netatmo_battery.js):%f]" icon="battery"

what am I missing to get the icon to show up correctly?

@Josar I like the member of option now, however I need to upgrade to OH2.2 then and that require some planning

0 Likes

(Rich Koshak) #13

Grrrr. I thought that the JavaScript would return an integer but it is returning a float.

return(Math.round(i*20));

Then use label="Netatmo Bedroom Battery status [JS(netatmo_battery.js):%s %%]"

That will fix the icon problem.

Or not. The Icon is based on the actual state of the Item, not just its transformed label. You will either need to make new battery icons that go from 0 to 5 or you will need to use the Rule.

0 Likes

(Josar) #14

inch pincher! NA != NaN :joy:
Or was this on purpose?

(function(i) {
    if( isNaN(i) ) return "NaN";
    return( Math.round(i*20) );
})(input)
0 Likes

(Kim Skatun) #15

I was hoping it was possible to do transform directly on the item…

0 Likes

(Rich Koshak) #16

It was on purpose. For the sitemap, I usually try to use something a little more human meaningful. Only a programmer would know that “NaN” means “Not a Number”, but “NA” is pretty universally understood (in English at least) as “Not Applicable.” I suppose for consistency I should return “-” so the Item looks like it is NULL, but that could cause other confusion.

0 Likes

(Josar) #17

Thanks for the clarification. As non native english speaker i just thought this must be an obvious error.

0 Likes

(Rich Koshak) #18

Most of the users on this forum are so proficient in English I sometimes let slip in too many idioms.

0 Likes