AppDaemon Addon - Folder path issue on 0.17

Hello,

I have been running a couple scripts on AppDaemon 0.16 for some month, but I can’t get them to work on 0.17.

My appdaemon.yaml is under \addon_configs\a0d7b954_appdaemon

and looks like this:

appdaemon:
  latitude: xx.xx
  longitude: xx.xx
  elevation: 8
  time_zone: Europe/Berlin
  
  thread_pool_size: 3  # Optional: Increase the number of threads for callbacks
  plugins:
    HASS:
      type: hass
      ha_url: "http://homeassistant-l11.local:8123"
      token: "xxx"
http:
  url: http://127.0.0.1:5050
admin:
api:
hadashboard:

My Apps are nicely under \config\appdaemon\apps

All that works on 0.16.7.

When updating AppDaemon to 0.17.x, I get:

2025-07-05 07:08:42.611227 WARNING AppDaemon: ------------------------------------------------------------
2025-07-05 07:08:42.611418 WARNING AppDaemon: Unexpected error during run()
2025-07-05 07:08:42.611578 WARNING AppDaemon: ------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3.12/site-packages/appdaemon/__main__.py", line 157, in run
    loop.run_until_complete(asyncio.gather(*pending))
  File "/usr/lib/python3.12/asyncio/base_events.py", line 691, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/site-packages/appdaemon/utility_loop.py", line 148, in loop
    await self.AD.app_management.check_app_updates(mode=UpdateMode.INIT)
  File "/usr/lib/python3.12/site-packages/appdaemon/app_management.py", line 814, in check_app_updates
    await self.check_app_config_files(update_actions)
  File "/usr/lib/python3.12/site-packages/appdaemon/app_management.py", line 619, in check_app_config_files
    self.config_filecheck.log_changes(self.logger, self.AD.app_dir)
  File "/usr/lib/python3.12/site-packages/appdaemon/models/internal/file_check.py", line 93, in log_changes
    logger.debug("New app config file: %s", file.relative_to(app_dir.parent))
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/pathlib.py", line 682, in relative_to
    raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
ValueError: '/homeassistant/appdaemon/apps/apps.yaml' is not in the subpath of '/config'
2025-07-05 07:08:42.614922 INFO AppDaemon: Previous message repeated 1 times

I did try to change

appdaemon:
  app_dir: /config/appdaemon/apps

but no improvement
Could someone guide me (better than chatGPT ;-))?

maybe something from this post can help you

Adding

  app_dir: /homeassistant/appdaemon/apps

Seems to work.
I now have a different issue.
My app was downloading and extracting info from a pdf (energy price).
With 0.16, the journal was clearly mentioning extracted values.
In 0.17 I just read initialized successfully!, but it’s not extracting anything (and I suppose it might be linked to apps download folders)

Is initialize() being called?
If you only see App XYZ: Initialized successfully but no logs from your PDF scraping meybe is not be inside initialize() or a scheduled callback.

If you switched to async def initialize(self) or are using async libraries, you must await calls or AppDaemon may silently skip parts of the method.

Add self.log(" — ") inside each key step to confirm execution
raise log level with

log:
  log_level: DEBUG

paste your app’s initialize() and extraction function, to take a look

AppDaemon 0.17 introduced improvements to app lifecycle management and asynchronous event handling, which can impact how initialize() and scheduled tasks behave.

edit—

add verbose logs in your app inside initialize or the PDF task
self.log("Starting PDF extraction...", level="INFO")

Thanks for helping me.
To be honest, I got ChatGPT to write the app for me, so I am only understanding half of what it is doing. :slight_smile:

import appdaemon.plugins.hass.hassapi as hass
import requests
import pdfplumber  # Using pdfplumber instead of fitz
import io
import re

class LuminusPrice(hass.Hass):
    def initialize(self):
        """ Initialize the AppDaemon app. """
        self.log("🔄 LuminusPrice app initializing...")

        # Load configuration from apps.yaml
        self.url = self.args.get("url")
        self.refresh_time = self.args.get("refresh_time")

        if not self.url:
            self.log("❌ URL is not configured in apps.yaml!", level="ERROR")
            return
        if not self.refresh_time:
            self.log("❌ Refresh time is not configured in apps.yaml!", level="ERROR")
            return

        # Home Assistant Sensor
        self.sensor_name = "sensor.gaz_prix_luminus_energie_tvac_pdf_parsed"

        # Schedule price updates based on the configured refresh time
        self.run_every(self.update_price, "now", self.refresh_time)

        self.log("✅ LuminusPrice initialized successfully!")

    def update_price(self, kwargs):
        self.log("🔄 update_price triggered")  # <-- Add this line
        """ Fetches the gas price from Luminus, extracts it, and updates HA. """
        try:
            self.log(f"📡 Fetching Luminus Gas Price from {self.url}...")

            response = requests.get(self.url)
            response.raise_for_status()  # Raise an exception for bad responses

            with pdfplumber.open(io.BytesIO(response.content)) as pdf:
                price = self.extract_price(pdf)
                
            if price:
                self.log(f"✅ Price found: {price}")
                self.set_state(
                    self.sensor_name, 
                    state=price, 
                    attributes={
                        "friendly_name": "Gaz - Prix - Luminus - Energie TVAc (PDF)",
                        "icon": "mdi:file-pdf-box",
                        "unit_of_measurement": "c€/kWh",
                        "device_class": "monetary",
                        "state_class": "measurement",
                        "description": "Extracted from Luminus PDF"
                    }
                )
            else:
                self.log("⚠️ Price not found!", level="WARNING")

        except Exception as e:
            self.log(f"❌ Error fetching price: {e}", level="ERROR")

    def extract_price(self, pdf):
        """ Extracts the gas price from the Luminus PDF. """
        target_row = "Energie (c€/kWh)"

        for page in pdf.pages:
            text = page.extract_text()
            if text:
                lines = text.split("\n")

                for i, line in enumerate(lines):
                    if target_row in line:
                        self.log(f"✅ Row found: {line}")

                        match = re.search(r"\(c€/kWh\)\s+([\d,]+)", line)
                        if match:
                            return match.group(1).replace(",", ".")

                        if i + 1 < len(lines):
                            next_line = lines[i + 1].strip().split()
                            if next_line:
                                return next_line[0].replace(",", ".")

        return None  # Price not found

The log tells me that:

2025-07-05 09:36:16.507316 INFO AppDaemon: Calling initialize() for luminus_price

2025-07-05 09:36:16.508818 INFO luminus_price: ���� LuminusPrice app initializing...

2025-07-05 09:36:16.510451 INFO luminus_price: ��� LuminusPrice initialized successfully!

2025-07-05 09:36:16.511213 INFO AppDaemon: App initialization complete

With AppDaemon 0.16, the following lines appear:

2025-07-05 09:49:39.476215 INFO luminus_price: ���� update_price triggered

2025-07-05 09:49:39.477474 INFO luminus_price: ���� Fetching Luminus Gas Price from https://www.luminus.be/api-next/get-pricelist?documentSlug=basicfix&energyType=gas&language=de

“now” is not a valid argument in AppDaemon

Replace this line

self.run_every(self.update_price, "now", self.refresh_time)

with

self.run_every(self.update_price, self.datetime(), self.refresh_time)

If you wanted to start at a specific time of day like 3 AM

self.run_every(self.update_price, "03:00:00", self.refresh_time)

Make sure refresh_time in apps.yaml is a duration string (like “00:30:00” for 30 minutes), which run_every() can parse.

let me know if this work

btw remove emojis on your logging

edit *********
also make sure your self.refresh_time is integer number like

self.refresh_time = 3600

1 Like

got it!
thanks