How to return number instead of String?

Hello
I m using Pyscript to create a sensor.
Here is a code:


"""
Test PyScript — sensor returning the current minute.

Sensor: sensor.testowy1
Value: current minute as a number (0–59)
Update: every minute
"""

from datetime import datetime


@time_trigger("cron(* * * * *)")
def update_testowy_sensor():
    """
    Updates the test sensor every minute.
    Returns the current minute as a number.
    """
    current_minute = float(datetime.now().minute)

    log.info(f"Updating sensor.testowy1: minute = {current_minute}")

    # Set the sensor with the value as float (numeric)
    state.set("sensor.testowy2", current_minute,
             attributes={
                 "friendly_name": "Test Sensor - Minute",
                 "unit_of_measurement": "min",
                 "state_class": "measurement",
                 "icon": "mdi:clock-outline",
                 "last_update": datetime.now().isoformat()
             })


@service
def force_update_testowy():
    """
    Manually forces an update of the test sensor.
    Call: service pyscript.force_update_testowy
    """
    log.info("Forced update of sensor.testowy1")
    update_testowy_sensor()


@event_trigger("homeassistant_start")
def startup_testowy_sensor():
    """
    Automatically updates the test sensor after HA startup.
    """
    log.info("HOME ASSISTANT START — Creating sensor.testowy1")
    import time
    time.sleep(5)  # Short delay
    update_testowy_sensor()

But it looks like the value is ‘stirng’ not number, and when i want to plot that i see


insted of plot.
How to fix that?

The state of a sensor is always a string. There is no way to “fix” that: it is by design.

The plot is shown that way because your sensor does not have a unit of measurement. I see that you’ve tried to set one, but for some reason it hasn’t worked.

EDIT: got it. state.set() doesn’t have an attributes argument. It’s new_attributes:

https://hacs-pyscript.readthedocs.io/en/stable/reference.html#state-variable-functions

That’s also why your graph is headed “testowy2” with an “eye” icon: the friendly_name and the icon are also not set for the same reason.

Sets the state variable to the given value, with the optional attributes. The optional 3rd argument, new_attributes, should be a dict and it will overwrite all the existing attributes if specified. If instead attributes are specified using keyword arguments, then just those attributes will be set and other attributes will not be affected.

You should set it the first time like this:

    state.set("sensor.testowy2", current_minute,
              new_attributes={
                 "friendly_name": "Test Sensor - Minute",
                 "unit_of_measurement": "min",
                 "state_class": "measurement",
                 "icon": "mdi:clock-outline",
                 "last_update": datetime.now().isoformat()
             })

Then update it like this:

    state.set("sensor.testowy2", current_minute,
              last_update=datetime.now().isoformat())

Hey
So my sensor.testowy2 has proper attributes


it has even unit of measurement, but still doesnt work.

I took your advice and create this code:

"""
Test PyScript — sensor returning the current minute.

Sensor: sensor.testowy2
Value: current minute as a number (0–59)
Update: every minute
"""

from datetime import datetime


SENSOR = "sensor.testowy3"


def set_sensor_attributes():
    """Set sensor attributes (run once at startup)."""
    state.set(
        SENSOR,
        float(datetime.now().minute),
        new_attributes={
            "friendly_name": "Test Sensor - Minute",
            "unit_of_measurement": "min",
            "state_class": "measurement",
            "icon": "mdi:clock-outline",
        },
    )


@time_trigger("cron(* * * * *)")
def update_testowy_sensor():
    """Updates the test sensor every minute."""
    current_minute = float(datetime.now().minute)

    log.info(f"Updating {SENSOR}: minute = {current_minute}")

    # Update only value + last_update attribute
    state.set(
        SENSOR,
        current_minute,
        last_update=datetime.now().isoformat(),
    )


@service
def force_update_testowy():
    """Manually forces an update of the test sensor."""
    log.info(f"Forced update of {SENSOR}")
    update_testowy_sensor()


@event_trigger("homeassistant_start")
def startup_testowy_sensor():
    """Initialize sensor after HA startup."""
    log.info("HOME ASSISTANT START — Creating test sensor")

    import time
    time.sleep(5)

    set_sensor_attributes()
    update_testowy_sensor()

and it is worse i d say, because I have (no attributes like unit_of_measurement, state_class itp)

you’re missing device_class. You need all 3 for it to be a numeric result. state_class, device_class, and unit_of_measurement.

as an aside, you can do the same thing here without the need for pyscript with way less configuration.

template:
- sensor:
  - name: minute
    state: "{{ now().minute }}"
    device_class: None
    state_class: measurement
    unit_of_measurement: min

it didnt help

I know i can do same thing easier, its just an example… I just want to make it number not string :expressionless:

You’re doing something wrong here: your attributes for testowy2 and testowy4 are under a dictionary key called attributes.

Compare your screenshot of the states page above with mine:

image

See the “attributes:” at the top of your right-most column? Shouldn’t be there.

Try also setting last_value in your setup function. I wonder if not pre-defining it is then wiping all of the ones you set in new_attributes?

1 Like

If you want the sensor’s graph to appear as a line chart, instead of a bar chart, the sensor must have device_class and unit_of_measurement options with appropriate values.

template:
- sensor:
  - name: Example
    state: "{{ now().minute }}"
    device_class: duration
    unit_of_measurement: min


To be clear, the sensor’s state value is still a string (as is the case for all entities). It is the presence of the two options, with appropriate values, that influences the UI to display the sensor’s values with a line chart instead of a bar chart.

Thank you so much!
This works:

"""
PyScript – ręcznie wywoływany sensor

Usługa: pyscript.ustaw_sensor
Tworzy/aktualizuje: sensor.pyscript_test
"""

from datetime import datetime

@service
def ustaw_sensor():
    current_minute = float(datetime.now().minute)
    state.set("sensor.pyscript_test2", current_minute,
        new_attributes={
            "friendly_name": "opis Sensor",
            "unit_of_measurement": "min",
            "state_class": "measurement",
            "icon": "mdi:clock-outline",
        }
    )

@123 @petro — whilst it might be good practice to set device_class and state_class, I have plenty of sensors with neither (unless they’re implicit and hidden), just a unit_of_measurement, that show up as a graph:

I agree. The bare minimum is that one option to influence the UI to use a line chart.

1 Like

Typically, if you use a state_class it must be accompanied with the other attributes that match the state_class.

I personally always offer complete examples because op may be coming back here asking why they don’t have statistics next.

1 Like