from __future__ import annotations
import asyncio
+import logging
import os
import urllib.parse
from collections.abc import AsyncGenerator
# start the webserver
self.publish_port = config.get_value(CONF_BIND_PORT)
self.publish_ip = config.get_value(CONF_PUBLISH_IP)
+ # print a big fat message in the log where the streamserver is running
+ # because this is a common source of issues for people with more complex setups
+ self.logger.log(
+ logging.INFO if self.mass.config.onboard_done else logging.WARNING,
+ "\n\n################################################################################\n"
+ "Starting streamserver on %s:%s\n"
+ "This is the IP address that is communicated to players.\n"
+ "If this is incorrect, audio will not play!\n"
+ "See the documentation how to configure the publish IP for the Streamserver\n"
+ "in Settings --> Core modules --> Streamserver\n"
+ "################################################################################\n",
+ self.publish_ip,
+ self.publish_port,
+ )
await self._server.setup(
bind_ip=config.get_value(CONF_BIND_IP),
bind_port=self.publish_port,
self.publish_port = config.get_value(CONF_BIND_PORT)
self.publish_ip = default_publish_ip
bind_ip = config.get_value(CONF_BIND_IP)
+ # print a big fat message in the log where the webserver is running
+ # because this is a common source of issues for people with more complex setups
+ if not self.mass.config.onboard_done:
+ self.logger.warning(
+ "\n\n################################################################################\n"
+ "Starting webserver on %s:%s - base url: %s\n"
+ "If this is incorrect, see the documentation how to configure the Webserver\n"
+ "in Settings --> Core modules --> Webserver\n"
+ "################################################################################\n",
+ bind_ip,
+ self.publish_port,
+ base_url,
+ )
+ else:
+ self.logger.info(
+ "Starting webserver on %s:%s - base url: %s\n#\n",
+ bind_ip,
+ self.publish_port,
+ base_url,
+ )
await self._server.setup(
bind_ip=bind_ip,
bind_port=self.publish_port,
def call() -> tuple[str, ...]:
result: list[tuple[int, str]] = []
+ # try to get the primary IP address
+ # this is the IP address of the default route
+ _sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ _sock.settimeout(0)
+ try:
+ # doesn't even have to be reachable
+ _sock.connect(("10.254.254.254", 1))
+ primary_ip = _sock.getsockname()[0]
+ except Exception:
+ primary_ip = ""
+ finally:
+ _sock.close()
+ # get all IP addresses of all network interfaces
adapters = ifaddr.get_adapters()
for adapter in adapters:
for ip in adapter.ips:
if ip_str.startswith(("::1", "::ffff:", "fe80")):
# filter out IPv6 loopback/link-local address
continue
- if ip_str.startswith(("192.168.",)):
+ if ip_str == primary_ip:
+ score = 10
+ elif ip_str.startswith(("192.168.",)):
# we rank the 192.168 range a bit higher as its most
# often used as the private network subnet
score = 2
return await asyncio.to_thread(call)
+async def get_primary_ip_address() -> str | None:
+ """Return the primary IP address of the system."""
+
+
async def is_port_in_use(port: int) -> bool:
"""Check if port is in use."""
"max_field_size": MAX_LINE_SIZE,
},
)
- self.logger.info("Starting server on %s:%s - base url: %s", bind_ip, bind_port, base_url)
self._apprunner = web.AppRunner(self._webapp, access_log=None, shutdown_timeout=10)
# add static routes
if self._static_routes: