Use /data directory for .esphome folder when running as HA add-on (#5374)

This commit is contained in:
Jesse Hills 2023-09-12 09:26:48 +12:00 committed by GitHub
parent 10eee47b6b
commit fe81bcc003
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 53 additions and 43 deletions

View file

@ -35,11 +35,16 @@ if bashio::config.has_value 'default_compile_process_limit'; then
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=$(bashio::config 'default_compile_process_limit')
else
if grep -q 'Raspberry Pi 3' /proc/cpuinfo; then
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1;
export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1
fi
fi
mkdir -p "${pio_cache_base}"
if bashio::fs.directory_exists '/config/esphome/.esphome'; then
bashio::log.info "Removing old .esphome directory..."
rm -rf /config/esphome/.esphome
fi
bashio::log.info "Starting ESPHome dashboard..."
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon

View file

@ -98,10 +98,9 @@ def validate_truetype_file(value):
def _compute_local_font_dir(name) -> Path:
base_dir = Path(CORE.config_dir) / ".esphome" / DOMAIN
h = hashlib.new("sha256")
h.update(name.encode())
return base_dir / h.hexdigest()[:8]
return Path(CORE.data_dir) / DOMAIN / h.hexdigest()[:8]
def _compute_gfonts_local_path(value) -> Path:

View file

@ -52,7 +52,7 @@ Image_ = image_ns.class_("Image")
def _compute_local_icon_path(value) -> Path:
base_dir = Path(CORE.config_dir) / ".esphome" / DOMAIN / "mdi"
base_dir = Path(CORE.data_dir) / DOMAIN / "mdi"
return base_dir / f"{value[CONF_ICON]}.svg"

View file

@ -87,12 +87,7 @@ def get_firmware(value):
url = value[CONF_URL]
if CONF_SHA256 in value: # we have a hash, enable caching
path = (
Path(CORE.config_dir)
/ ".esphome"
/ DOMAIN
/ (value[CONF_SHA256] + "_fw_stm.bin")
)
path = Path(CORE.data_dir) / DOMAIN / (value[CONF_SHA256] + "_fw_stm.bin")
if not path.is_file():
firmware_data, dl_hash = dl(url)

View file

@ -554,6 +554,12 @@ class EsphomeCore:
def config_dir(self):
return os.path.dirname(self.config_path)
@property
def data_dir(self):
if is_ha_addon():
return os.path.join("/data")
return self.relative_config_path(".esphome")
@property
def config_filename(self):
return os.path.basename(self.config_path)
@ -563,7 +569,7 @@ class EsphomeCore:
return os.path.join(self.config_dir, path_)
def relative_internal_path(self, *path: str) -> str:
return self.relative_config_path(".esphome", *path)
return os.path.join(self.data_dir, *path)
def relative_build_path(self, *path):
path_ = os.path.expanduser(os.path.join(*path))
@ -573,13 +579,9 @@ class EsphomeCore:
return self.relative_build_path("src", *path)
def relative_pioenvs_path(self, *path):
if is_ha_addon():
return os.path.join("/data", self.name, ".pioenvs", *path)
return self.relative_build_path(".pioenvs", *path)
def relative_piolibdeps_path(self, *path):
if is_ha_addon():
return os.path.join("/data", self.name, ".piolibdeps", *path)
return self.relative_build_path(".piolibdeps", *path)
@property

View file

@ -198,8 +198,8 @@ def preload_core_config(config, result):
CORE.data[KEY_CORE] = {}
if CONF_BUILD_PATH not in conf:
conf[CONF_BUILD_PATH] = f".esphome/build/{CORE.name}"
CORE.build_path = CORE.relative_config_path(conf[CONF_BUILD_PATH])
conf[CONF_BUILD_PATH] = f"build/{CORE.name}"
CORE.build_path = CORE.relative_internal_path(conf[CONF_BUILD_PATH])
has_oldstyle = CONF_PLATFORM in conf
newstyle_found = [key for key in TARGET_PLATFORMS if key in config]

View file

@ -32,6 +32,7 @@ import yaml
from tornado.log import access_log
from esphome import const, platformio_api, util, yaml_util
from esphome.core import CORE
from esphome.helpers import get_bool_env, mkdir_p, run_system_command
from esphome.storage_json import (
EsphomeStorageJSON,
@ -70,6 +71,7 @@ class DashboardSettings:
self.password_hash = password_hash(password)
self.config_dir = args.configuration
self.absolute_config_dir = Path(self.config_dir).resolve()
CORE.config_path = os.path.join(self.config_dir, ".")
@property
def relative_url(self):
@ -534,7 +536,7 @@ class DownloadListRequestHandler(BaseHandler):
@authenticated
@bind_config
def get(self, configuration=None):
storage_path = ext_storage_path(settings.config_dir, configuration)
storage_path = ext_storage_path(configuration)
storage_json = StorageJSON.load(storage_path)
if storage_json is None:
self.send_error(404)
@ -577,7 +579,7 @@ class DownloadBinaryRequestHandler(BaseHandler):
def get(self, configuration=None):
compressed = self.get_argument("compressed", "0") == "1"
storage_path = ext_storage_path(settings.config_dir, configuration)
storage_path = ext_storage_path(configuration)
storage_json = StorageJSON.load(storage_path)
if storage_json is None:
self.send_error(404)
@ -666,9 +668,7 @@ class DashboardEntry:
@property
def storage(self) -> Optional[StorageJSON]:
if not self._loaded_storage:
self._storage = StorageJSON.load(
ext_storage_path(settings.config_dir, self.filename)
)
self._storage = StorageJSON.load(ext_storage_path(self.filename))
self._loaded_storage = True
return self._storage
@ -1044,9 +1044,9 @@ class DeleteRequestHandler(BaseHandler):
@bind_config
def post(self, configuration=None):
config_file = settings.rel_path(configuration)
storage_path = ext_storage_path(settings.config_dir, configuration)
storage_path = ext_storage_path(configuration)
trash_path = trash_storage_path(settings.config_dir)
trash_path = trash_storage_path()
mkdir_p(trash_path)
shutil.move(config_file, os.path.join(trash_path, configuration))
@ -1067,7 +1067,7 @@ class UndoDeleteRequestHandler(BaseHandler):
@bind_config
def post(self, configuration=None):
config_file = settings.rel_path(configuration)
trash_path = trash_storage_path(settings.config_dir)
trash_path = trash_storage_path()
shutil.move(os.path.join(trash_path, configuration), config_file)
@ -1325,10 +1325,9 @@ def make_app(debug=get_bool_env(ENV_DEV)):
def start_web_server(args):
settings.parse_args(args)
mkdir_p(settings.rel_path(".esphome"))
if settings.using_auth:
path = esphome_storage_path(settings.config_dir)
path = esphome_storage_path()
storage = EsphomeStorageJSON.load(path)
if storage is None:
storage = EsphomeStorageJSON.get_default()

View file

@ -35,7 +35,7 @@ def run_git_command(cmd, cwd=None) -> str:
def _compute_destination_path(key: str, domain: str) -> Path:
base_dir = Path(CORE.config_dir) / ".esphome" / domain
base_dir = Path(CORE.data_dir) / domain
h = hashlib.new("sha256")
h.update(key.encode())
return base_dir / h.hexdigest()[:8]

View file

@ -22,19 +22,19 @@ _LOGGER = logging.getLogger(__name__)
def storage_path() -> str:
return CORE.relative_internal_path(f"{CORE.config_filename}.json")
return os.path.join(CORE.data_dir, "storage", f"{CORE.config_filename}.json")
def ext_storage_path(base_path: str, config_filename: str) -> str:
return os.path.join(base_path, ".esphome", f"{config_filename}.json")
def ext_storage_path(config_filename: str) -> str:
return os.path.join(CORE.data_dir, "storage", f"{config_filename}.json")
def esphome_storage_path(base_path: str) -> str:
return os.path.join(base_path, ".esphome", "esphome.json")
def esphome_storage_path() -> str:
return os.path.join(CORE.data_dir, "esphome.json")
def trash_storage_path(base_path: str) -> str:
return os.path.join(base_path, ".esphome", "trash")
def trash_storage_path() -> str:
return CORE.relative_config_path("trash")
class StorageJSON:

View file

@ -6,12 +6,12 @@ import unicodedata
import voluptuous as vol
import esphome.config_validation as cv
from esphome.const import ALLOWED_NAME_CHARS, ENV_QUICKWIZARD
from esphome.core import CORE
from esphome.helpers import get_bool_env, write_file
from esphome.log import color, Fore
from esphome.log import Fore, color
from esphome.storage_json import StorageJSON, ext_storage_path
from esphome.util import safe_print
from esphome.const import ALLOWED_NAME_CHARS, ENV_QUICKWIZARD
CORE_BIG = r""" _____ ____ _____ ______
/ ____/ __ \| __ \| ____|
@ -193,10 +193,10 @@ captive_portal:
def wizard_write(path, **kwargs):
from esphome.components.esp8266 import boards as esp8266_boards
from esphome.components.esp32 import boards as esp32_boards
from esphome.components.rp2040 import boards as rp2040_boards
from esphome.components.bk72xx import boards as bk72xx_boards
from esphome.components.esp32 import boards as esp32_boards
from esphome.components.esp8266 import boards as esp8266_boards
from esphome.components.rp2040 import boards as rp2040_boards
from esphome.components.rtl87xx import boards as rtl87xx_boards
name = kwargs["name"]
@ -225,7 +225,7 @@ def wizard_write(path, **kwargs):
write_file(path, wizard_file(**kwargs))
storage = StorageJSON.from_wizard(name, name, f"{name}.local", hardware)
storage_path = ext_storage_path(os.path.dirname(path), os.path.basename(path))
storage_path = ext_storage_path(os.path.basename(path))
storage.save(storage_path)
return True
@ -265,9 +265,9 @@ def strip_accents(value):
def wizard(path):
from esphome.components.bk72xx import boards as bk72xx_boards
from esphome.components.esp32 import boards as esp32_boards
from esphome.components.esp8266 import boards as esp8266_boards
from esphome.components.bk72xx import boards as bk72xx_boards
from esphome.components.rtl87xx import boards as rtl87xx_boards
if not path.endswith(".yaml") and not path.endswith(".yml"):
@ -280,6 +280,9 @@ def wizard(path):
f"Uh oh, it seems like {color(Fore.CYAN, path)} already exists, please delete that file first or chose another configuration file."
)
return 2
CORE.config_path = path
safe_print("Hi there!")
sleep(1.5)
safe_print("I'm the wizard of ESPHome :)")

View file

@ -1,7 +1,9 @@
"""Tests for the wizard.py file."""
import os
import esphome.wizard as wz
import pytest
from esphome.core import CORE
from esphome.components.esp8266.boards import ESP8266_BOARD_PINS
from esphome.components.esp32.boards import ESP32_BOARD_PINS
from esphome.components.bk72xx.boards import BK72XX_BOARD_PINS
@ -110,6 +112,7 @@ def test_wizard_write_sets_platform(default_config, tmp_path, monkeypatch):
# Given
del default_config["platform"]
monkeypatch.setattr(wz, "write_file", MagicMock())
monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path))
# When
wz.wizard_write(tmp_path, **default_config)
@ -130,6 +133,7 @@ def test_wizard_write_defaults_platform_from_board_esp8266(
default_config["board"] = [*ESP8266_BOARD_PINS][0]
monkeypatch.setattr(wz, "write_file", MagicMock())
monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path))
# When
wz.wizard_write(tmp_path, **default_config)
@ -150,6 +154,7 @@ def test_wizard_write_defaults_platform_from_board_esp32(
default_config["board"] = [*ESP32_BOARD_PINS][0]
monkeypatch.setattr(wz, "write_file", MagicMock())
monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path))
# When
wz.wizard_write(tmp_path, **default_config)
@ -170,6 +175,7 @@ def test_wizard_write_defaults_platform_from_board_bk72xx(
default_config["board"] = [*BK72XX_BOARD_PINS][0]
monkeypatch.setattr(wz, "write_file", MagicMock())
monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path))
# When
wz.wizard_write(tmp_path, **default_config)
@ -190,6 +196,7 @@ def test_wizard_write_defaults_platform_from_board_rtl87xx(
default_config["board"] = [*RTL87XX_BOARD_PINS][0]
monkeypatch.setattr(wz, "write_file", MagicMock())
monkeypatch.setattr(CORE, "config_path", os.path.dirname(tmp_path))
# When
wz.wizard_write(tmp_path, **default_config)