Skip to content

Regression on set_state api call #2531

Description

@jfparis

What happened?

A little while back I posted about a regression with the set_state api call. (issue #2464 )

Whilst some changes were made the issue is still here for me. Every time I set a state, every attribute that is equal to False or 0 will be ignored

I created a small applet below

If you run that code with version 4.5.11, you get an entity with the following attributes

rate: 0
friendly_name: Test Entity
unit_of_measurement: GBP/kWh
plunge: false
plunge_start: false

If you run it with 4.5.12 or 4.5.13 you get the following attributes

friendly_name: Test Entity
unit_of_measurement: GBP/kWh

Version

4.5.13

Installation type

Python virtual environment

Relevant log output

Relevant code in the app or config file that caused the issue

Test.yaml

test_case:
  module: test
  class: TestApp



Test.py

import appdaemon.plugins.hass.hassapi as hass

class TestApp(hass.Hass):

    def initialize(self):
        self.log("run test app")
        attributes = {
            "rate": 0,
            "friendly_name": "Test Entity",
            "unit_of_measurement": "GBP/kWh",
            "plunge": False,
            "plunge_start": False,
        }

        self.set_state(
            "sensor.test_case_sensor",
            1,
            attributes=attributes,
            replace = True,
        )


Config file

ppdaemon:
  time_zone: Europe/London
  latitude: 51
  longitude: 0
  elevation: 20
  plugins:
    HASS:
      type: hass
      ha_url: http://localhost:8123
      token: somethingsomething

Anything else?

No response

Activity

  1. mikkelke commented on Jul 15, 2026

    @mikkelke

    Edit: this analysis applies to the released 4.5.13 only — the bug is already fixed on dev by #2594, confirmed by an end-to-end test in my follow-up below. Reopen request withdrawn.


    Just hit this independently on a fresh 4.5.13 install (Docker) and can confirm it's not fixed — reproduces exactly as described above, with a minimal repro that doesn't even need a running HA instance:

    $ docker exec appdaemon python -c "import appdaemon.utils as u; print(u.clean_http_kwargs({'attributes':{'flag_false':False,'flag_true':True,'count':0}}))"
    {'attributes': {'flag_true': 'true'}}
    

    flag_false and count (0) are gone; flag_true survives but as the string "true", not a JSON bool.

    Current source is unchanged from what's already quoted in #2464:

    # appdaemon/utils.py
    def clean_http_kwargs(val: Any) -> Any:
        """Recursively cleans the kwarg dict to prepare it for use in HTTP requests."""
        cleaned = clean_kwargs(val, http=True)
        pruned = remove_literals(cleaned, (None, False))
        return pruned

    I think this is why #2475 (titled "only clean query parameters") didn't actually close this out: HassPlugin.http_method calls clean_http_kwargs unconditionally, before branching on HTTP method:

    # appdaemon/plugins/hass/hassplugin.py, http_method()
    kwargs = utils.clean_http_kwargs(kwargs)
    ...
    match method.lower():
        case "get":
            http_method = functools.partial(self.session.get, params=kwargs)
        case "post":
            http_method = functools.partial(self.session.post, json=kwargs)
        case "delete":
            http_method = functools.partial(self.session.delete, params=kwargs)

    So the False/0-dropping, True-stringifying cleanup (which makes sense for a GET query string) still runs on the kwargs that become the POST JSON body via set_state/call_service, contrary to the PR's own description ("There is no need to 'clean' the json body of a POST request... that wasn't done in 4.4.x"). Moving the clean_http_kwargs call inside the "get"/"delete" branches only, and leaving "post"'s kwargs as real Python types (maybe just a datetime→isoformat pass for JSON-serializability), looks like it would fix this without touching GET/DELETE query-param handling.

    #2640 suggests this is still affecting people in the wild as recently as last month, also on 4.5.13. Could this be reopened, given it reproduces identically to the original report on the exact version it was closed against?


    Root-cause tracing and this write-up were AI-assisted (Claude).

  2. jfparis commented on Jul 15, 2026

    @jfparis
    Author

    4.5.13 was released back in january. Patch for this issue was applied in May so 4.5.13 definitely has the bug. You might want to test on the github version (I confess I have not done so)

  3. mikkelke commented on Jul 15, 2026

    @mikkelke

    @jfparis Confirmed — I just tested the GitHub dev version end-to-end (throwaway container, pip install of the dev tarball → 4.5.14-dev, pointed at a live HA instance), publishing via set_state(..., replace=True):

    attributes={
        "probe_false": False,
        "probe_true": True,
        "probe_zero": 0,
        "probe_zero_float": 0.0,
        "probe_none": None,
        "probe_str": "x",
    }

    HA's /api/states afterwards:

    "attributes": {
        "probe_false": false,
        "probe_true": true,
        "probe_zero": 0,
        "probe_zero_float": 0.0,
        "probe_none": null,
        "probe_str": "x"
    }

    Everything preserved, with real JSON types — note true is a proper boolean again, not the string "true" that 4.5.12/4.5.13 produce. The fix is #2594 ("Fix set_state dropping False, 0, and None values", merged to dev 2026-05-13 — the same day this issue was closed, so the closure was right and my reopen request above is withdrawn): on dev, POST bodies are no longer cleaned at all, query-param cleaning moved to a dedicated clean_http_params_for_urlencode(), and remove_literals() now uses identity checks to dodge the 0 == False pitfall.

    So the only remaining gap is a release — 4.5.13 (2026-01-19) predates the fix and is still the latest, which is presumably why this keeps getting re-reported from released installs (#2640). Maintainers: any chance of cutting a release that includes #2594?

    Testing and write-up were AI-assisted.

  4. acockburn commented on Jul 15, 2026

    @acockburn
    Member

    We will have a release soon.

  5. Ten0 commented on Sep 6, 2026

    @Ten0
    Contributor

    Still blocked on 4.4 - a version from 2 years ago - due to this. Would it be possible to get a release?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    issueSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions