HA Restarts - How to maintain state(+attributes) set by API call

I have an external program calling the HA API to read and set states (energy related).

So this uses an endpoint like “home-assistant.local/api/states/ENTITY” on which it performs get to read the current state and state attributes.
And it performs a post on that endpoint to update the state and its attributes. The python code looks like this:

            data = {
                "state": meter_m3_total,
                "attributes": {
                    "date_time": date_time.isoformat(),
                    "unit_of_measurement": "m³",
                    "device_class": "gas",
                    "state_class": "total_increasing",
                    "last_check": now_isostr,
                },
            }
            r = self.open_url(
                HA_API_SENSOR_FORMAT % (sensor_name_generic_m3,), data
            )

However after HA restart these entities / state values and attributes are lost.

What is the best way to keep those values survive a restart.

You can’t. That API is only intended for use in testing and development, not as a permanent way of getting data into a production system. Can you actually use that sensor in the energy dashboard? I didn’t think you could since its not really a sensor.

Only integrations can create sensors since there must by a python class that inherits from SensorEntity defining that sensor entity. “entities” created via that API have no maching python class, they are just random dictionaries in the state machine. It doesn’t matter if they start with sensor., the corresponding python class is what makes it a sensor.

If you are dead set on doing it this way the only way to get your data to survive a restart is to define a matching trigger template sensor for each one in your configuration.yaml. Each will look like this:

template:
  - trigger:
      platform: state
      entity_id: sensor.my_external_m3_data
    sensor:
      name: My m3 data
      state: "{{ trigger.to_state.state }}"
      unit_of_measurement: m³
      device_class: gas
      state_class: total_increasing
      attributes:
        date_time: "{{ trigger.to_state.attributes.date_time }}"
        ...

You get the idea. Basically duplicate everything into this template sensor. Repeat for every entity you are creating via that API.

It must be a trigger template sensor, not a regular template sensor. Because regular template sensors do not survive restart either so you’ll have the same problem. Trigger template sensors do though so this one will work like a regular state-based template sensor except it survives restart.

Alternatively, consider writing an integration for HA. You don’t have to actually merge your personal integration into core, you can just put the code into the custom_components folder. Then your integration can handle communication with your devices and make actual sensor entities with restore state capability (and any other entities you want). This is how HA was designed to work, integrations create and manage all entities.

If writing a custom integration is too much work then you can cheat a bit with mqtt. Have your external program send mqtt discovery messages defining the entities for your devices. And then have it push state updates to the mqtt broker with retain = true. Then you will get true sensors in HA that will survive restart (since they will see the retained messages immediately on startup and get back in the same state).

1 Like

Thank you for your prompt reply

Yes, it’s been running since a month, and I’ve been using it for another sensor where the previous state is not important (as the utility provider is providing a total) which has been running for about a year.

It’s already an AppDaemon application to be able to use selenium under HAOS, and the script on AppDaemon calls another python script that actually does the work. Selenium does not work as a custom_integration.

So what is “too much” is that there must be so many layers to make things work. Adding a template sensor that duplicates something that we can essentially already do “almost” directly on the API…

It looks like “As Is” learning MQTT is mandatory.

Oh you’re using AppDaemon. AppDaemon can do it then I believe. AppDaemon does not need to use that API to add state to HA, it can make real sensors and other entities directly. That’s what the AppDaemon addon does.

If you have a docker or core install which does not support addons then take a look at how that that addon sets up AppDaemon. You should be able to replicate it in your standalone install and get AppDaemon more deeply integrated with HA. Then you’ll be able to define and manage sensors right from the code and I believe those should survive restart.

I admit I don’t have much experience with AppDaemon so if you have issues here you might need to ask in #third-party:appdaemon . Hopefully someone there has ideas.

EDIT: I’m realizing that getting sensor data to persist from AppDaemon may be harder then I anticipated. Sorry that is my naivety with it. I assumed it worked a lot like Node RED in that regard, sensors created from Node RED persist by default if you use the corresponding HACS component. But I’m realizing there doesn’t seem to be an equivalent for AppDaemon.

This post has a reply you might find useful. And this one suggests there is an example app showing how its done. Hopefully that’s enough to get you started or else maybe another can provide some insight with more experience here.

Yes, I am using AppDaemon, but not everybody can - I use AppDaemon mainly as a method to avoid another instance somewhere to use selenium, but some will not have HAOS and not use AppDaemon.

So I do not want to rely on AppDaemon to set states in HA which means another layer with another interface to HA to maintain and provide support for (vs. the interface that installations without AppDaemon use).
Therefore, here AppDaemon is just a wrapper around a script that needs Selenium (and thus a browser), and not a bridge between the script and Home Assistant.

What interface are you referring to? Like I said before, integrations set states. Integrations are part of the python process of HA. There effectively is no API for setting states. The one you found is the only one and it has severe limitations since it isn’t intended for extended use outside of dev and test (it doesn’t create real entities, state doesn’t survive restart, etc.)

In the typical HA all entities are made and managed by integrations. Those are set up either in the GUI or in configuration.yaml. When you configure an integration HA then loads then python module corresponding to that integration into its process and runs particular known methods so it can be initialized. It then creates all the entities it expects based on the config, handles communication with external devices or services and uses those communications to keep the entities up to date.

Interfaces:

  • “Selenium script” → Home Assistant REST API;
  • “Selenium script” → AppDaemon → Home Assistant (through the hass python api).

I am thinking that adding a command_line sensor defining the attributes as json_attributes and some dummy script path that is never called might do the trick as well since I have such a sensor that still has all of its values despite the fact that I have not triggered it since a long time… .
It avoids defining templates and values for the attributes as they will be set through the REST API.

Adding

- platform: command_line
  name: gas_consumption_kwh
  command: dummy
  scan_interval: 100000000
  unit_of_measurement: kWh
  #device_class: energy
  #state_class: total_increasing

- platform: command_line
  name: gas_consumption_m3
  command: dummy
  scan_interval: 100000000
  unit_of_measurement: m³

to replace

- platform: template
  sensors:
    gas_consumption_kwh:
      friendly_name: "Gaz (kWh)"
      unit_of_measurement: kWh
      device_class: energy
      value_template: "{{ states('counter.gas_consumption') }}"
    gas_consumption_m3:
      friendly_name: "Gaz (m³)"
      unit_of_measurement: m³
      device_class: gas
      value_template: "{{ states('counter.gas_consumption') | float / 11.16 }}"

That were defined a long time ago, but no longer defined just crreate new sensors (indexed with _2).

And I noticed that other sensors that I created using the API do maintain their values across HA restarts (and they are not defined as a sensor in YAML nor elsewhere).

My goal was to keep my long term history on these entities (gas_consumption_kwh and gas_consumption_m3). I suspect that they still are defined as template sensors (in the database).

So I’ll check:

  • That the state of a new entity defined through the API survives a HA restart or not;
  • Perform some DB operations to copy the historical data (statistics) from the original entities to entities defined through the API and use those for the Energy panel.

It does not maintain the state of API defined “entities”, I was misleaded by the browser cache (in Developer Tools>State).

Command line entities don’t inherit from RestoreEntity so they don’t survive restart either:

The ones that restore their state after restart inherit from this class:

I don’t really understand your plan with the dummy command line entities. But since they don’t survive restart either I’m not sure how they help here.

There’s a sensor from another integration that is no longer active (since months) that is still maintaining state and it’s a command line sensor.

I don’t understand what this means. There’s a command line integration. It makes command line sensors. Nothing else makes command line sensors because there is only one command line integration. Another integration can make sensors but they won’t be command line sensors, they will be sensors from integration <x>.

Sensors from other integrations can certainly restore state. I showed you how they do it, in the python class they inherit from RestoreEntity. But sensors created by the command line integration do not do that.

This is the sensor

- platform: command_line
  name: GRDF consommation gaz
  command: /config/gazpar/gazpar_ha.sh sensor
  scan_interval: 100000000
  unit_of_measurement: kWh
  json_attributes:
    - conso_m3
    - conso_kWh
    - index_kWh
    - index_m3
    - date
    - log
  value_template: '{{ value_json.index_kWh }}'

And this is a copy of the state:

So the state still has its value after multiple reboots. Maybe this sensor is still working at start up, but the automation that was forcing this sensor to update is no longer enabled.

Command line sensors run the specified command on every startup of HA to set their state. After that the next time they run the command is based on scan_interval (so in your case every 100000000 seconds that HA has been running). But scan_interval only matters after startup.

They always run their command on startup to set their initial state, there is no way to stop that. They do that instead of using the restore state option since they assume the state can always be reconstituted by simply running the command.

@CentralCommand
Thank you for all your feedback.

I now retain state information in a json file managed by the external script in order to maintain the correct metering totals.

1 Like