Skip to content

Commit c1aed46

Browse files
committed
chore: improve error msg on home assistant add-on port config
When running as a Home Assistant add-on the ports shall not be changed as this would break config.yaml that is used by Home Assistant. Prevent the change and return an error message. Also fix date file setup. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
1 parent 64928db commit c1aed46

10 files changed

Lines changed: 122 additions & 88 deletions

File tree

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ DOCKER_COMPOSE_DATA_DIR=${HOME}/.local/share/net.akkudoktor.eos
1111
# -----------------------------------------------------------------------------
1212
# Image / build
1313
# -----------------------------------------------------------------------------
14-
VERSION=0.3.0.dev2603180781250771
14+
VERSION=0.3.0.dev2603271452975993
1515
PYTHON_VERSION=3.13.9
1616

1717
# -----------------------------------------------------------------------------

config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# the root directory (no add-on folder as usual).
77

88
name: "Akkudoktor-EOS"
9-
version: "0.3.0.dev2603180781250771"
9+
version: "0.3.0.dev2603271452975993"
1010
slug: "eos"
1111
description: "Akkudoktor-EOS add-on"
1212
url: "https://github.com/Akkudoktor-EOS/EOS"

docs/_generated/configserver.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
| Name | Environment Variable | Type | Read-Only | Default | Description |
99
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
10-
| eosdash_host | `EOS_SERVER__EOSDASH_HOST` | `Optional[str]` | `rw` | `None` | EOSdash server IP address. Defaults to EOS server IP address. |
11-
| eosdash_port | `EOS_SERVER__EOSDASH_PORT` | `Optional[int]` | `rw` | `None` | EOSdash server IP port number. Defaults to EOS server IP port number + 1. |
10+
| eosdash_host | `EOS_SERVER__EOSDASH_HOST` | `str` | `rw` | `127.0.0.1` | EOSdash server IP address. Defaults to EOS server IP address. |
11+
| eosdash_port | `EOS_SERVER__EOSDASH_PORT` | `int` | `rw` | `8504` | EOSdash server IP port number. Defaults to 8504. |
1212
| eosdash_supervise_interval_sec | `EOS_SERVER__EOSDASH_SUPERVISE_INTERVAL_SEC` | `int` | `rw` | `10` | Supervision interval for EOS server to supervise EOSdash [seconds]. |
13-
| host | `EOS_SERVER__HOST` | `Optional[str]` | `rw` | `127.0.0.1` | EOS server IP address. Defaults to 127.0.0.1. |
14-
| port | `EOS_SERVER__PORT` | `Optional[int]` | `rw` | `8503` | EOS server IP port number. Defaults to 8503. |
13+
| host | `EOS_SERVER__HOST` | `str` | `rw` | `127.0.0.1` | EOS server IP address. Defaults to 127.0.0.1. |
14+
| port | `EOS_SERVER__PORT` | `int` | `rw` | `8503` | EOS server IP port number. Defaults to 8503. |
1515
| reload | `EOS_SERVER__RELOAD` | `Optional[bool]` | `rw` | `False` | Enable server auto-reload for debugging or development. Default is False. Monitors the package directory for changes and reloads the server. |
1616
| run_as_user | `EOS_SERVER__RUN_AS_USER` | `Optional[str]` | `rw` | `None` | The name of the target user to switch to. If ``None`` (default), the current effective user is used and no privilege change is attempted. |
1717
| startup_eosdash | `EOS_SERVER__STARTUP_EOSDASH` | `Optional[bool]` | `rw` | `True` | EOS server to start EOSdash server. Defaults to True. |

docs/_generated/openapi.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Akkudoktor-EOS
22

3-
**Version**: `v0.3.0.dev2603180781250771`
3+
**Version**: `v0.3.0.dev2603271452975993`
44

55
<!-- pyml disable line-length -->
66
**Description**: This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period.

openapi.json

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"name": "Apache 2.0",
99
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
1010
},
11-
"version": "v0.3.0.dev2603180781250771"
11+
"version": "v0.3.0.dev2603271452975993"
1212
},
1313
"paths": {
1414
"/v1/admin/cache/clear": {
@@ -8327,14 +8327,7 @@
83278327
"ServerCommonSettings": {
83288328
"properties": {
83298329
"host": {
8330-
"anyOf": [
8331-
{
8332-
"type": "string"
8333-
},
8334-
{
8335-
"type": "null"
8336-
}
8337-
],
8330+
"type": "string",
83388331
"title": "Host",
83398332
"description": "EOS server IP address. Defaults to 127.0.0.1.",
83408333
"default": "127.0.0.1",
@@ -8344,14 +8337,7 @@
83448337
]
83458338
},
83468339
"port": {
8347-
"anyOf": [
8348-
{
8349-
"type": "integer"
8350-
},
8351-
{
8352-
"type": "null"
8353-
}
8354-
],
8340+
"type": "integer",
83558341
"title": "Port",
83568342
"description": "EOS server IP port number. Defaults to 8503.",
83578343
"default": 8503,
@@ -8386,32 +8372,20 @@
83868372
"default": true
83878373
},
83888374
"eosdash_host": {
8389-
"anyOf": [
8390-
{
8391-
"type": "string"
8392-
},
8393-
{
8394-
"type": "null"
8395-
}
8396-
],
8375+
"type": "string",
83978376
"title": "Eosdash Host",
83988377
"description": "EOSdash server IP address. Defaults to EOS server IP address.",
8378+
"default": "127.0.0.1",
83998379
"examples": [
84008380
"127.0.0.1",
84018381
"localhost"
84028382
]
84038383
},
84048384
"eosdash_port": {
8405-
"anyOf": [
8406-
{
8407-
"type": "integer"
8408-
},
8409-
{
8410-
"type": "null"
8411-
}
8412-
],
8385+
"type": "integer",
84138386
"title": "Eosdash Port",
8414-
"description": "EOSdash server IP port number. Defaults to EOS server IP port number + 1.",
8387+
"description": "EOSdash server IP port number. Defaults to 8504.",
8388+
"default": 8504,
84158389
"examples": [
84168390
8504
84178391
]

scripts/update_version.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import sys
1111
from datetime import timezone
1212
from pathlib import Path
13-
from typing import List
13+
from typing import List, Optional
1414

1515
PROJECT_ROOT = Path(__file__).parent.parent
1616
PACKAGE_DIR = PROJECT_ROOT / "src" / "akkudoktoreos"
@@ -102,7 +102,7 @@ def repl(match):
102102
return file_would_be_updated
103103

104104

105-
def update_version_date_file() -> str:
105+
def update_version_date_file() -> Optional[str]:
106106
"""Write current version date to _version_date.py, only if changed."""
107107
from akkudoktoreos.core.version import VERSION_DATE_FILE, _version_date_hash
108108
version_date, _ = _version_date_hash()
@@ -112,7 +112,7 @@ def update_version_date_file() -> str:
112112

113113
if VERSION_DATE_FILE.exists() and VERSION_DATE_FILE.read_text(encoding="utf-8") == new_content:
114114
print(f"No change to {VERSION_DATE_FILE}")
115-
return str(VERSION_DATE_FILE)
115+
return None
116116

117117
VERSION_DATE_FILE.write_text(new_content, encoding="utf-8")
118118
print(f"Updated {VERSION_DATE_FILE} with UTC date {version_date_str}")
@@ -134,18 +134,12 @@ def main(version: str, files: List[str]):
134134
if update_version_in_file(path, version):
135135
updated_files.append(str(path))
136136

137+
version_date_file = update_version_date_file()
138+
if version_date_file:
139+
updated_files.append(version_date_file)
140+
137141
if updated_files:
138142
print(f"Updated files: {', '.join(updated_files)}")
139-
140-
# Only update VERSION_DATE_FILE if a real package file was touched
141-
# Exclude VERSION_DATE_FILE itself to avoid a self-referencing loop
142-
from akkudoktoreos.core.version import VERSION_DATE_FILE
143-
package_files_updated = any(
144-
str(PACKAGE_DIR) in f and Path(f).resolve() != VERSION_DATE_FILE.resolve()
145-
for f in updated_files
146-
)
147-
if package_files_updated:
148-
updated_files.append(update_version_date_file())
149143
else:
150144
print("No files updated.")
151145

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
VERSION_DATE = "2026-02-24T16:58:00Z"
1+
VERSION_DATE = "2026-03-27T14:59:30+00:00"

src/akkudoktoreos/server/server.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
import re
88
import socket
99
import time
10-
from typing import Optional
10+
from typing import Any, Optional
1111

1212
import psutil
1313
from loguru import logger
1414
from pydantic import Field, field_validator
1515

16-
from akkudoktoreos.config.configabc import SettingsBaseModel
16+
from akkudoktoreos.config.configabc import SettingsBaseModel, is_home_assistant_addon
1717
from akkudoktoreos.core.coreabc import get_config
1818

1919

@@ -22,6 +22,11 @@ def get_default_host() -> str:
2222
return "127.0.0.1"
2323

2424

25+
def get_default_port() -> int:
26+
"""Default port for EOS."""
27+
return 8503
28+
29+
2530
def get_host_ip() -> str:
2631
"""IP address of the host machine.
2732
@@ -326,15 +331,15 @@ def fix_data_directories_permissions(run_as_user: Optional[str] = None) -> None:
326331
class ServerCommonSettings(SettingsBaseModel):
327332
"""Server Configuration."""
328333

329-
host: Optional[str] = Field(
334+
host: str = Field(
330335
default=get_default_host(),
331336
json_schema_extra={
332337
"description": "EOS server IP address. Defaults to 127.0.0.1.",
333338
"examples": ["127.0.0.1", "localhost"],
334339
},
335340
)
336-
port: Optional[int] = Field(
337-
default=8503,
341+
port: int = Field(
342+
default=get_default_port(),
338343
json_schema_extra={
339344
"description": "EOS server IP port number. Defaults to 8503.",
340345
"examples": [
@@ -349,17 +354,17 @@ class ServerCommonSettings(SettingsBaseModel):
349354
default=True,
350355
json_schema_extra={"description": "EOS server to start EOSdash server. Defaults to True."},
351356
)
352-
eosdash_host: Optional[str] = Field(
353-
default=None,
357+
eosdash_host: str = Field(
358+
default=get_default_host(),
354359
json_schema_extra={
355360
"description": "EOSdash server IP address. Defaults to EOS server IP address.",
356361
"examples": ["127.0.0.1", "localhost"],
357362
},
358363
)
359-
eosdash_port: Optional[int] = Field(
360-
default=None,
364+
eosdash_port: int = Field(
365+
default=get_default_port() + 1,
361366
json_schema_extra={
362-
"description": "EOSdash server IP port number. Defaults to EOS server IP port number + 1.",
367+
"description": "EOSdash server IP port number. Defaults to 8504.",
363368
"examples": [
364369
8504,
365370
],
@@ -406,12 +411,34 @@ def validate_server_host(cls, value: Optional[str]) -> Optional[str]:
406411
value = validate_ip_or_hostname(value)
407412
return value
408413

409-
@field_validator("port", "eosdash_port")
410-
def validate_server_port(cls, value: Optional[int]) -> Optional[int]:
411-
if value is not None and not (1024 <= value <= 49151):
414+
@field_validator("port", mode="before")
415+
def validate_server_port(cls, value: Any) -> int:
416+
default_port = get_default_port()
417+
if value is None:
418+
return default_port
419+
value = int(value)
420+
if is_home_assistant_addon() and value != default_port:
421+
raise ValueError(
422+
f"Server port number `{default_port}` for Home Assistant add-on can not be changed."
423+
)
424+
if not (1024 <= value <= 49151):
412425
raise ValueError("Server port number must be between 1024 and 49151.")
413426
return value
414427

428+
@field_validator("eosdash_port", mode="before")
429+
def validate_eosdash_port(cls, value: Any) -> int: # ← unique name
430+
default_port = get_default_port() + 1
431+
if value is None:
432+
return default_port
433+
value = int(value)
434+
if is_home_assistant_addon() and value != default_port:
435+
raise ValueError(
436+
f"EOSdash port number `{default_port}` for Home Assistant add-on can not be changed."
437+
)
438+
if not (1024 <= value <= 49151):
439+
raise ValueError("EOSdash port number must be between 1024 and 49151.")
440+
return value
441+
415442
@field_validator("run_as_user")
416443
def validate_user(cls, value: Optional[str]) -> Optional[str]:
417444
if value is not None:

tests/test_server.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,16 @@
1111
import requests
1212
from conftest import cleanup_eos_eosdash
1313
from loguru import logger
14+
from pydantic import ValidationError
1415

16+
from akkudoktoreos.config.configabc import is_home_assistant_addon
1517
from akkudoktoreos.core.version import __version__
16-
from akkudoktoreos.server.server import get_default_host, wait_for_port_free
18+
from akkudoktoreos.server.server import (
19+
ServerCommonSettings,
20+
get_default_host,
21+
get_default_port,
22+
wait_for_port_free,
23+
)
1724

1825

1926
class TestServer:
@@ -45,6 +52,38 @@ def test_server_setup_for_class(self, server_setup_for_class):
4552
assert str(data_ouput_path).startswith(eos_dir)
4653

4754

55+
class TestServerSettingsValidation:
56+
"""Test the port restrictions in ServerCommonSettings when running as HA addon."""
57+
58+
def test_ha_addon_default_ports_ok(self, config_eos, monkeypatch):
59+
"""Default ports are accepted in HA addon mode."""
60+
monkeypatch.setattr('akkudoktoreos.server.server.is_home_assistant_addon', lambda: True)
61+
assert config_eos.server.port == get_default_port() # 8503
62+
assert config_eos.server.eosdash_port == get_default_port() + 1 # 8504
63+
64+
def test_server_port_restriction_in_ha_addon(self, config_eos, monkeypatch):
65+
"""Server port must be the default (8503) in HA addon mode."""
66+
monkeypatch.setattr('akkudoktoreos.server.server.is_home_assistant_addon', lambda: True)
67+
with pytest.raises(ValidationError) as excinfo:
68+
config_eos.server.port = 9000
69+
assert "Server port number `8503` for Home Assistant add-on can not be changed" in str(excinfo.value)
70+
71+
def test_eosdash_port_restriction_in_ha_addon(self, config_eos, monkeypatch):
72+
"""EOSdash port must be the default (8504) in HA addon mode."""
73+
monkeypatch.setattr('akkudoktoreos.server.server.is_home_assistant_addon', lambda: True)
74+
with pytest.raises(ValidationError) as excinfo:
75+
config_eos.server.eosdash_port = 9001
76+
assert "EOSdash port number `8504` for Home Assistant add-on can not be changed" in str(excinfo.value)
77+
78+
def test_ports_allowed_when_not_ha_addon(self, config_eos):
79+
"""Custom ports are allowed when not in HA addon mode."""
80+
# is_home_assistant_addon() returns False by default in this test environment
81+
config_eos.server.port = 9000
82+
config_eos.server.eosdash_port = 9001
83+
assert config_eos.server.port == 9000
84+
assert config_eos.server.eosdash_port == 9001
85+
86+
4887
class TestServerStartStop:
4988

5089
@pytest.mark.asyncio

0 commit comments

Comments
 (0)