Skip to content

Got a ClientResponse error after updating from AppDaemon 0,17.10 to 0.17.12 #2487

@wdriessen

Description

@wdriessen

What happened?

I have some code that creates some energy sensors. This code worked fine for several years now, but after updating to AppDeamon version 0.17.12 I get an error when calling self.set_state()

The complete error logged after starting the code class below is as follows:

025-11-10 16:20:17.790386 INFO EnergyDailyUsage: Unexpected error setting sensor.delivered_low_day: argument of type 'ClientResponseError' is not iterable

My class is as follows:

import appdaemon.plugins.hass.hassapi as hass
import datetime
from pytz import timezone
from aiohttp import ClientResponseError

class EnergyDailyUsage(hass.Hass):

    def initialize(self):
        self.trace = False
        self._trace("initialize", "started")

        self.id_ch = self.args["consume_high"]
        self.id_cl = self.args["consume_low"]
        self.id_dh = self.args["deliver_high"]
        self.id_dl = self.args["deliver_low"]
        self.id_gas = self.args["gas"]

        self.startDay = {}
        self.startMonth = {}
        self.startYear = {}

        self.energyfilestore = self.get_app('EnergyFileStore')

        self.run_daily(self.callback, datetime.time(0, 0, 0))
        self.run_at(self.callback, datetime.datetime.now() + datetime.timedelta(seconds=2))
        self.run_in(self._timertick, 60)

        self.listen_state(self._tracemode, "input_boolean.trace_mode")
        self.turn_off("input_boolean.trace_mode")

    def _safe_float(self, value):
        try:
            return float(value)
        except (TypeError, ValueError):
            return 0.0

    def _tracemode(self, entity, attribute, old, new, kwargs):
        self.trace = new == 'on'
        self._trace("_tracemode()", f"Trace mode {'on' if self.trace else 'off'}")

    def callback(self, kwargs):
        self._trace("callback", "started")
        self._check_scope('day')
        self._check_scope('month')
        self._check_scope('year')

    def _check_scope(self, scope):
        data = self.energyfilestore.GetEnergyStart(scope == 'day', scope == 'month', scope == 'year')
        now = datetime.datetime.now(timezone('Europe/Amsterdam'))

        if "dt" in data:
            if (
                (scope == 'day' and data['dt'].date() != now.date()) or
                (scope == 'month' and data['dt'].month != now.month) or
                (scope == 'year' and data['dt'].year != now.year)
            ):
                self._trace(f"_check_{scope}", f"Different {scope.capitalize()}")
                self._store_startvalues(scope)
            else:
                self._trace(f"_check_{scope}", f"Same {scope.capitalize()}")
        else:
            self._store_startvalues(scope)

        setattr(self, f"start{scope.capitalize()}", data)

    def _store_startvalues(self, scope):
        tz = timezone('Europe/Amsterdam')
        now = datetime.datetime.now(tz=tz)
        record = {
            'dt': now,
            'gas': self.get_state(self.id_gas),
            'ch': self.get_state(self.id_ch),
            'cl': self.get_state(self.id_cl),
            'dh': self.get_state(self.id_dh),
            'dl': self.get_state(self.id_dl),
        }

        self.energyfilestore.SetEnergyStart(
            record,
            scope == 'day',
            scope == 'month',
            scope == 'year'
        )
        setattr(self, f"start{scope.capitalize()}",
                self.energyfilestore.GetEnergyStart(
                    scope == 'day',
                    scope == 'month',
                    scope == 'year'
                ))

    def _timertick(self, args):
        if self._check_if_values_ready():
            self._create_and_save('day', self.startDay)
            self._create_and_save('month', self.startMonth)
            self._create_and_save('year', self.startYear)
        self.run_in(self._timertick, 60)

    def _check_if_values_ready(self):
        for sensor in [self.id_ch, self.id_cl, self.id_dh, self.id_dl, self.id_gas]:
            if self.get_state(sensor) == 'unknown':
                return False
        return True

    def _create_and_save(self, scope, start_data):
        suffix = f"_{scope}"
        now_vals = {
            'ch': self._safe_float(self.get_state(self.id_ch)),
            'cl': self._safe_float(self.get_state(self.id_cl)),
            'dh': self._safe_float(self.get_state(self.id_dh)),
            'dl': self._safe_float(self.get_state(self.id_dl)),
            'gas': self._safe_float(self.get_state(self.id_gas)),
        }

        deltas = {k: now_vals[k] - self._safe_float(start_data.get(k)) for k in now_vals}

        if 'ch' in start_data:
            self._set_energy_sensor(f"sensor.consumed_high{suffix}", deltas['ch'], f"{scope.capitalize()}s Consumed Electricity High", "kWh")
        if 'cl' in start_data:
            self._set_energy_sensor(f"sensor.consumed_low{suffix}", deltas['cl'], f"{scope.capitalize()}s Consumed Electricity Low", "kWh")
        if 'dh' in start_data:
            self._set_energy_sensor(f"sensor.delivered_high{suffix}", deltas['dh'], f"{scope.capitalize()}s Delivered Electricity High", "kWh")
        if 'dl' in start_data:
            self._set_energy_sensor(f"sensor.delivered_low{suffix}", deltas['dl'], f"{scope.capitalize()}s Delivered Electricity Low", "kWh")
        if 'gas' in start_data:
            self._set_energy_sensor(f"sensor.consumed_gas{suffix}", deltas['gas'], f"{scope.capitalize()}s Consumed Gas", "m3")

        if 'ch' in start_data and 'cl' in start_data:
            consumed = deltas['ch'] + deltas['cl']
            self._set_energy_sensor(f"sensor.consumed{suffix}", consumed, f"{scope.capitalize()}s Consumed Electricity", "kWh")
        if 'dh' in start_data and 'dl' in start_data:
            delivered = deltas['dh'] + deltas['dl']
            self._set_energy_sensor(f"sensor.delivered{suffix}", delivered, f"{scope.capitalize()}s Delivered Electricity", "kWh")
        if all(k in start_data for k in ('ch', 'cl', 'dh', 'dl')):
            netto = (deltas['ch'] + deltas['cl']) - (deltas['dh'] + deltas['dl'])
            self._set_energy_sensor(f"sensor.netto{suffix}", netto, f"{scope.capitalize()}s Netto Electricity", "kWh")

    def _set_energy_sensor(self, name, value, friendly_name, unit):
        self._trace("_set_energy_sensor", f"Name = {name}")
        try:
            self.set_state(
                entity_id=name,
                state=round(value, 3),
                attributes={
                    "friendly_name": friendly_name,
                    "unit_of_measurement": unit
                }
            )
        except ClientResponseError as e:
            self.error(f"Failed to set state for {name}: {e.status} {e.message}")
        except Exception as e:
            self.error(f"Unexpected error setting {name}: {e}")

    def _trace(self, function, message):
        if self.trace:
            self.log(f"{function} -> {message}")

Gr, Will

Version

4.5.12

Installation type

Home Assistant add-on

Relevant log output

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

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions