Skip to content

Commit

Permalink
Merge pull request #580 from maxwroc/RssiExample
Browse files Browse the repository at this point in the history
KString abs function for RSSI entities #401
  • Loading branch information
maxwroc authored Oct 22, 2023
2 parents 151b103 + 91c828d commit 9286239
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 28 deletions.
58 changes: 35 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This card was inspired by [another great card](https://github.com/cbulock/lovela
<details>
<summary>Update to v3.X.X</summary>

* Secondary info last_updated / last_changed values. Now these values has to be put in curly braces e.g. `secondary_info: "{last_updated}"`
* Secondary info last_updated / last_changed values. Now these values has to be put in quotes and curly braces e.g. `secondary_info: "{last_updated}"`
* Secondary info charging indication. Now the value has to be in curly braces e.g. `secondary_info: "{charging}"`
* Sorting setting has changed. Now it is called `sort` (previously "sort_by_level") and it can define multiple levels of sorting.
* Color settings are now in a single config entry `colors` ("color_thresholds" and "color_gradient" settings are not working any more)
Expand Down Expand Up @@ -51,6 +51,12 @@ collapse: 8
bulk_rename:
- from: " Battery"
- from: " level"
colors:
steps:
- '#ff0000'
- '#ffff00'
- '#00ff00'
gradient: true
```
### Card config
Expand All @@ -75,7 +81,6 @@ bulk_rename:
| icon | string | | v1.6.0 | Icon override (if you want to set a static custom one). You can provide entity attribute name which contains icon class (e.g. `attributes.battery_icon` - it has to be prefixed with "attributes.")
| attribute | string | | v0.9.0 | Name of attribute (override) to extract the value from. By default we look for values in the following attributes: `battery_level`, `battery`. If they are not present we take entity state.
| multiplier | number | `1` | v0.9.0 | If the value is not in 0-100 range we can adjust it by specifying multiplier. E.g. if the values are in 0-10 range you can make them working by putting `10` as multiplier.
| value_override | [KString](#keyword-string-kstring) | | v3.0.0 | Allows to override the battery level value. Note: when used the `multiplier`, `round`, `state_map` setting is ignored

+[common options](#common-options) (if specified they will override the card-level ones)

Expand All @@ -91,6 +96,7 @@ These options can be specified both per-entity and at the top level (affecting a
| secondary_info | [KString](#keyword-string-kstring) | | v3.0.0 | Secondary info text. It can be a custom text with keywords (dynamic values) ([example](#secondary-info))
| round | number | | v2.1.0 | Rounds the value to number of fractional digits
| unit | string | `"%"` | v2.1.0 | Override for unit displayed next to the state/level value ([example](#other-use-cases))
| value_override | [KString](#keyword-string-kstring) | | v3.0.0 | Allows to override the battery level value. Note: when used the `multiplier`, `round`, `state_map` setting is ignored

### Keyword string (KString)

Expand All @@ -114,6 +120,7 @@ Keywords support simple functions to convert the values
| lessthan(\[threshold_number\],\[result_value\]) | `"{state\|lessthan(10,0)}"` | Changes the value to a given one when the threshold is met. In the given example the value will be replaced to 0 when the current value is less than 10
| between(\[lower_threshold_number\],[upper_threshold_number\],\[result_value\]) | `"{state\|between(2,6,30)}"` | Changes the value to a given one when the value is between two given numbers. In the given example the value will be replaced to 30 when the current value is between 2 and 6
| thresholds(\[number1\],\[number2\],...) | `"{state\|thresholds(22,89,200,450)}"` | Converts the value to percentage based on given thresholds. In the given example values will be converted in the following way 20=>0, 30=>25, 99=>50, 250=>75, 555=>100
| abs() | `"{state\|abs()}"` | Produces the absolute value

You can execute functions one after another. For example if you have the value "Battery level: 26.543234%" and you want to extract and round the number then you can do the following: `"{attribute.battery_level|replace(Battery level:=)|replace(%=)|round()} %"` and the end result will be "27"

Expand Down Expand Up @@ -536,7 +543,7 @@ filter:
```yaml
type: custom:battery-state-card
name: Secondary info
secondary_info: last_updated # applied to all entities which don't have the override
secondary_info: "{last_updated}" # applied to all entities which don't have the override
entities:
- entity: sensor.bedroom_motion_battery_level
name: "Bedroom motion sensor"
Expand Down Expand Up @@ -598,31 +605,34 @@ entities:

### Other use cases

![image](https://user-images.githubusercontent.com/8268674/147777101-c6f8a299-a03e-4792-a92c-8477b03d1941.png)
![image](https://github.com/maxwroc/battery-state-card/assets/8268674/d66bcd53-e37a-4518-a087-bd7e708b3425)

```yaml
type: custom:battery-state-card
title: Link quality
sort: "state"
secondary_info: '{last_changed}'
icon: mdi:signal
filter:
include:
- name: attributes.device_class
value: signal_strength
sort:
by: state
collapse: 8
bulk_rename:
- from: ' Signal'
- from: ' strength'
- from: ' Rssi'
- from: ' numeric'
value_override: '{state|abs()}'
colors:
steps:
- '#ff0000'
- '#ffff00'
- '#00ff00'
- color: '#00ff00'
value: 50
- color: '#ffff00'
value: 65
- color: '#ff0000'
value: 100
gradient: true
icon: mdi:signal
unit: lqi
entities:
- entity: sensor.bathroom_motion_signal
name: Bathroom motion sensor
- entity: sensor.bedroom_balcony_signal
name: Bedroom balkony door sensor
- entity: sensor.bedroom_motion_signal
name: Bedroom motion sensor
- entity: sensor.bedroom_switch_signal
name: Bedroom Aqara switch
- entity: sensor.bedroomtemp_signal
name: Bedroom temp. sensor
```
![image](https://user-images.githubusercontent.com/10567188/151678867-28bd47b9-fb66-42ed-a78a-390d55860634.png)

Expand All @@ -642,7 +652,9 @@ color_thresholds:
tap_action:
action: more-info
collapse: 3
sort_by_level: desc
sort:
by: state
desc: true
unit: °C
round: 0
filter:
Expand Down
2 changes: 1 addition & 1 deletion src/battery-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BatteryStateEntity } from "./custom-elements/battery-state-entity";
/**
* Properties which should be copied over to individual entities from the card
*/
const entititesGlobalProps: (keyof IBatteryEntityConfig)[] = [ "tap_action", "state_map", "charging_state", "secondary_info", "colors", "bulk_rename", "icon", "round", "unit" ];
const entititesGlobalProps: (keyof IBatteryEntityConfig)[] = [ "tap_action", "state_map", "charging_state", "secondary_info", "colors", "bulk_rename", "icon", "round", "unit", "value_override" ];

const regExpPattern = /\/([^/]+)\/([igmsuy]*)/;

Expand Down
6 changes: 5 additions & 1 deletion src/custom-elements/battery-state-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,9 @@ const getDefaultConfig = () => <IBatteryStateCardConfig>{
bulk_rename: [
{ from: " Battery" },
{ from: " level" },
]
],
colors: {
steps: [ "#ff0000", "#ffff00", "#00ff00" ],
gradient: true,
}
}
2 changes: 1 addition & 1 deletion src/custom-elements/battery-state-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class BatteryStateEntity extends LovelaceCard<IBatteryEntityConfig> {
this.name = getName(this.config, this.hass);
this.state = getBatteryLevel(this.config, this.hass);
if (isNumber(this.state)) {
this.unit = String.fromCharCode(160) + (this.config.unit || "%");
this.unit = String.fromCharCode(160) + (this.config.unit || this.hass?.states[this.config.entity]?.attributes["unit_of_measurement"] || "%");
}
else {
this.unit = undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/entity-fields/charging-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const getDefaultChargingState = (config: IBatteryEntityConfig, hass?: HomeAssist
return false;
}

return ["Charging", "charging"].includes(batteryStateEntity.state);
return ["charging", "full"].includes(batteryStateEntity.state);
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/rich-string-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ const availableProcessors: IMap<IProcessorCtor> = {

return Math.round(100 / thresholds.length * result).toString();
}
}
},
"abs": () =>
val => Math.abs(Number(val)).toString(),
}

interface IProcessor {
Expand Down
12 changes: 12 additions & 0 deletions test/other/rich-string-processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,16 @@ describe("RichStringProcessor", () => {
const result = proc.process(text);
expect(result).toBe(expectedResult);
});

test.each([
["{state|abs()}", "-64", "64"],
["{state|abs()}", "64", "64"],
])("abs function", (text: string, state:string, expectedResult: string) => {
const hassMock = new HomeAssistantMock<BatteryStateEntity>(true);
const motionEntity = hassMock.addEntity("Bedroom motion", state, {}, "sensor");
const proc = new RichStringProcessor(hassMock.hass, motionEntity.entity_id);

const result = proc.process(text);
expect(result).toBe(expectedResult);
});
})

0 comments on commit 9286239

Please sign in to comment.