Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[Home Assistant] Person card

I recently saw this cool dashboard and the person cards caught my eye. As the dashboard creator also provided all the yaml code and a really helpful guide, I tried to rebuild it. I was already using the mushroom-person-card, so I “just” had to add the little icons (mushroom-chips-card) below it (using the vertical-stack-in-card). To display the network type and the charging status, you first have to enable these sensors in the Home Assistant Companion App on your mobile phone. This is my result:

type: horizontal-stack
cards:
  - type: custom:vertical-stack-in-card
    cards:
      - type: custom:mushroom-person-card
        entity: person.nico
        icon_type: entity-picture
        secondary_info: last-changed
        card_mod:
          style: |
            ha-card {
              background: transparent;
            }
      - type: horizontal-stack
        cards:
          - type: custom:mushroom-chips-card
            alignment: center
            card_mod: 
              style: |
                ha-card {
                    --chip-font-size: 0.3em;
                    --chip-icon-size: 0.5em;
                    --chip-border-width: 0;
                    --chip-box-shadow: none;
                    --chip-background: none;
                    --chip-border: none;
                    --chip-spacing: none;
                    --chip-font-weight: bold;
                }
            chips:
              - type: template
                entity: sensor.mi_8_network_type
                content: '{{ states(''sensor.mi_8_network_type'')}}'                
                icon: |-
                  {% if is_state('sensor.mi_8_network_type','wifi')%}
                    mdi:wifi 
                  {% elif is_state('sensor.mi_8_network_type','vpn')%}
                    mdi:network
                  {% elif is_state('sensor.mi_8_network_type','cellular')%}
                    mdi:signal-4g
                  {% else %} 
                    mdi:network-strength-off
                  {% endif %}  
                icon_color: >-
                  {% if is_state('sensor.mi_8_network_type','wifi') or
                  is_state('sensor.mi_8_network_type','vpn')%}
                    green
                  {% elif is_state('sensor.mi_8_network_type','cellular')%}
                    red
                  {% else %} 
                    grey
                  {% endif %}   
                tap_action:
                  action: more-info
              - type: template
                entity: sensor.mi_8_battery_level
                content: '{{ states(''sensor.mi_8_battery_level'')}}%'
                icon: |-
                  {% set state = states('sensor.mi_8_battery_level')|float %}
                  {% if state >= 0 and state < 10 %} mdi:battery-10
                  {% elif state >= 10 and state < 20 %} mdi:battery-20
                  {% elif state >= 20 and state < 30 %} mdi:battery-30
                  {% elif state >= 30 and state < 40 %} mdi:battery-40
                  {% elif state >= 40 and state < 50 %} mdi:battery-50
                  {% elif state >= 50 and state < 60 %} mdi:battery-60
                  {% elif state >= 60 and state < 70 %} mdi:battery-70
                  {% elif state >= 70 and state < 80 %} mdi:battery-80
                  {% elif state >= 80 and state < 95 %} mdi:battery-90
                  {% else %} mdi:battery
                  {% endif %}   
                icon_color: |-
                  {% set state = states('sensor.mi_8_battery_level')|float %}
                  {% if state >= 0 and state < 20 %} red
                  {% elif state >= 20 and state < 50 %} orange
                  {% elif state >= 50 and state < 80 %} yellow
                  {% else %} green
                  {% endif %}         
                tap_action:
                  action: more-info
              - type: template
                entity: sensor.mi_8_battery_power
                content: '{{ states(''sensor.mi_8_battery_power'')}} W'
                icon: |-
                  {% if is_state('binary_sensor.mi_8_is_charging','on')%} 
                    mdi:power-plug  
                  {% else %} 
                    mdi:power-plug-off 
                  {% endif %}                  
                icon_color: |-
                  {% if is_state('binary_sensor.mi_8_is_charging','on')%} 
                    blue
                  {% else %} 
                    grey
                  {% endif %}
                tap_action:
                  action: more-info
  - type: custom:vertical-stack-in-card
    cards:
      - type: custom:mushroom-person-card
        entity: person.user2
        icon_type: entity-picture
        secondary_info: last-changed
        card_mod:
          style: |
            ha-card {
              background: transparent;
            }
      - type: horizontal-stack
        cards:
          - type: custom:mushroom-chips-card
            alignment: center
            card_mod: 
              style: |
                ha-card {
                    --chip-font-size: 0.3em;
                    --chip-icon-size: 0.5em;
                    --chip-border-width: 0;
                    --chip-box-shadow: none;
                    --chip-background: none;
                    --chip-border: none;
                    --chip-spacing: none;
                    --chip-font-weight: bold;
                }
            chips:
              - type: template
                entity: sensor.redmi_note_8_pro_network_type
                content: '{{ states(''sensor.redmi_note_8_pro_network_type'')}}'                
                icon: >-
                  {% if
                  is_state('sensor.redmi_note_8_pro_network_type','wifi')%}
                    mdi:wifi 
                  {% elif
                  is_state('sensor.redmi_note_8_pro_network_type','vpn')%}
                    mdi:network
                  {% elif
                  is_state('sensor.redmi_note_8_pro_network_type','cellular')%}
                    mdi:signal-4g
                  {% else %} 
                    mdi:network-strength-off
                  {% endif %}  
                icon_color: >-
                  {% if is_state('sensor.redmi_note_8_pro_network_type','wifi')
                  or is_state('sensor.redmi_note_8_pro_network_type','vpn')%}
                    green
                  {% elif
                  is_state('sensor.redmi_note_8_pro_network_type','cellular')%}
                    red
                  {% else %} 
                    grey
                  {% endif %}   
                tap_action:
                  action: more-info
              - type: template
                entity: sensor.mi_8_battery_level
                content: '{{ states(''sensor.redmi_note_8_pro_battery_level'')}}%'
                icon: >-
                  {% set state = states('sensor.redmi_note_8_pro_battery_level')|float %}
                  {% if state >= 0 and state < 10 %} mdi:battery-10
                  {% elif state >= 10 and state < 20 %} mdi:battery-20
                  {% elif state >= 20 and state < 30 %} mdi:battery-30
                  {% elif state >= 30 and state < 40 %} mdi:battery-40
                  {% elif state >= 40 and state < 50 %} mdi:battery-50
                  {% elif state >= 50 and state < 60 %} mdi:battery-60
                  {% elif state >= 60 and state < 70 %} mdi:battery-70
                  {% elif state >= 70 and state < 80 %} mdi:battery-80
                  {% elif state >= 80 and state < 95 %} mdi:battery-90
                  {% else %} mdi:battery
                  {% endif %}   
                icon_color: >-
                  {% set state = states('sensor.redmi_note_8_pro_battery_level')|float %}
                  {% if state >= 0 and state < 20 %} red
                  {% elif state >= 20 and state < 50 %} orange
                  {% elif state >= 50 and state < 80 %} yellow
                  {% else %} green
                  {% endif %}            
                tap_action:
                  action: more-info
              - type: template
                entity: sensor.redmi_note_8_pro_battery_power
                content: '{{ states(''sensor.redmi_note_8_pro_battery_power'')}} W'
                icon: >-
                  {% if is_state('binary_sensor.redmi_note_8_pro_is_charging','on')%} 
                    mdi:power-plug  
                  {% else %} 
                    mdi:power-plug-off 
                  {% endif %}                  
                icon_color: >-
                  {% if is_state('binary_sensor.redmi_note_8_pro_is_charging','on')%} 
                    blue
                  {% else %} 
                    grey
                  {% endif %}
                tap_action:
                  action: more-info

[Home Assistant] Template sensor which combines door lock and contact sensor

Cool template sensor idea I found here, which combines the states of two sensors and display the different combined states. Useful if, for example, you want to combine a door lock and a contact sensor on the same door.

Settings -> Devices & services -> Helpers -> Create Helper -> Template

{% if is_state('lock.kellertur', 'locked') and is_state('binary_sensor.kellertur_contact', 'off') %}
  Locked
{% elif is_state('lock.kellertur', 'unlocked') and is_state('binary_sensor.kellertur_contact', 'on') %}
  Open
{% elif is_state('lock.kellertur', 'unlocked') and is_state('binary_sensor.kellertur_contact', 'off') %}
  Closed, Unlocked
{% elif is_state('lock.kellertur', 'locked') and is_state('binary_sensor.kellertur_contact', 'on') %}
  Open, Locked 
{% else %}
  Unknown
{% endif %}

Helpful to check whether a door is really closed when locking it via a smart lock. Because else it could happen, that you would see status “Locked“, although the door is still open. But with this helper, you will get in this situation “Open, Locked“.

To emphasize such a situation even more clearly, you can of course also add some icon colors.

[CAP] Select max with group by

https://www.w3resource.com/sql/aggregate-functions/Max-with-group-by.php

https://answers.sap.com/questions/13081527/simple-count-aggregation-on-caps-cql.html?childToView=13079907&answerPublished=true

entity myEntity {
        key ID: Integer;
        key seqNr: Integer;
        key createdAt: DateTime;
        ...
    }

@readonly
entity myEntityMaxSeqNr 
        as select from myEntity {
            ID, 
            count(seqNr) as maxSeqNr: Integer
            createdAt,
            ...
            } 
        group by 
            ID,
            createdAt;

This can also be done using CQL like here.

[Home Assistant] Motion sensor in combination with Adaptive Lightning

I have some lights in my garden which are turned on in the night and are controlled by the Adaptive Lighting component, to automatically adjust brightness and color during the night. But if someone comes home late and this is detected by a motion sensor, I wanted to increase the brightness of all the lights in the garden for a short time.

Increasing the brightness was easy, as it can be done by using the light.turn_on service. However, it took me a few minutes to figure out how to reactivate adaptive lighting on these lights when motion is no longer detected. But it’s actually super simple (and it’s directly written on the GitHub start page here and here). You just have to deactivate the “manually controlled” flag that got activated by “manually” increasing the brightness. Following an example with a single motion sensor (binary_sensor.haustuer_motion), a lamp (light.haustur_light) and the adaptive lightning switch entity (switch.adaptive_lighting_haustuer).

alias: Motion sensor front door
description: "Increase brightness for three minutes when motion is detected"
trigger:
  - platform: state
    entity_id:
      - binary_sensor.haustuer_motion
    to: "on"
condition:
  - condition: state
    entity_id: sun.sun
    state: below_horizon
action:
  - service: light.turn_on
    data:
      transition: 3
      brightness_pct: 70
    target:
      entity_id: light.haustur_light
  - wait_for_trigger:
      - platform: state
        entity_id:
          - binary_sensor.haustuer_motion
        to: "off"
        for:
          hours: 0
          minutes: 3
          seconds: 0
    timeout:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 0
  - service: adaptive_lighting.set_manual_control
    data:
      manual_control: false
      entity_id: switch.adaptive_lighting_haustuer
      lights:
        - light.haustur_light
mode: single

[SAPUI5] Create date object in UTC YYYY-MM-ddTHH:mm:ss

https://sapui5.hana.ondemand.com/#/api/sap.ui.core.format.DateFormat%23methods/format

            const today = new Date()
            const oDateTimeFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({
                pattern: "yyyy-MM-ddTHH:mm:ss",
                UTC: true
            })
            const todayISO = oDateTimeFormat.format(today)

The UTC flag can also be set, when calling the format function.

            const today = new Date()
            const oDateTimeFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({
                pattern: "yyyy-MM-ddTHH:mm:ss",
                //UTC: true
            })
            const todayISO = oDateTimeFormat.format(today, true)

[SAPUI5] Adding Lanes to a Process Flow

Manually adding Lanes to a Process Flow Control:

https://sapui5.hana.ondemand.com/#/api/sap.suite.ui.commons.ProcessFlow
https://sapui5.hana.ondemand.com/#/api/sap.suite.ui.commons.ProcessFlowLaneHeader
https://sapui5.hana.ondemand.com/#/entity/sap.suite.ui.commons.ProcessFlow/sample/sap.suite.ui.commons.sample.ProcessFlowUpdateLanes/code

In my case, there was no way to bind the model to the view, so I did the mapping for each ProcessFlowLaneHeader in the callback function after reading the oData entity.

view.xml

<flow:ProcessFlow id="process-flow"/>

controller.js

var oProcessFlow = this.getView().byId("process-flow")

var oRequestFilter = new sap.ui.model.Filter({
    path: "myId",
    operator: sap.ui.model.FilterOperator.EQ,
    value1: myId
})

this.getView().getModel().read("/WorkflowSet", {
    filters: [oFormularIdFilter],
    success: (oData, response) => {
        for (var i = 0; i < oData.results.length; i++) {
            var oLaneHeader = new ProcessFlowLaneHeader({
                laneId: oData.results[i].LaneId,
                iconSrc: oData.results[i].IconSrc,
                text: oData.results[i].Text,
                position: oData.results[i].Position,
                state: [{state: oData.results[i].State, value: "100"}]
            });
            oProcessFlow.addLane(oLaneHeader)
        }
    },
    error: oError => {
        sap.m.MessageToast.show("An error occured while reading entity /WorkflowSet.")
    }
});

[SuccessFactors] Process Trigger

In a Process Trigger, you can get a good overview of an employee who moved from REC, via ONB to EC.

Manage Data -> Search -> Process Trigger

This information can also be fetched via API.

API Entity: ONB2Process

### Process Trigger
GET {{$dotenv sf_api_url}}/odata/v2/ONB2Process('06B129C95FD3482B851018D37B697149')
Authorization: Basic {{$dotenv sf_api_auth_base64}}
Accept: application/json

### processTriggerNav, includes rcmCandidateId, rcmApplicationId, rcmJobReqId
GET {{$dotenv sf_api_url}}/odata/v2/ONB2Process('06B129C95FD3482B851018D37B697149')
?$expand=processTriggerNav
Authorization: Basic {{$dotenv sf_api_auth_base64}}
Accept: application/json