""" Support to interface with Alexa Devices. SPDX-License-Identifier: Apache-2.0 For more details about this platform, please refer to the documentation at https://community.home-assistant.io/t/echo-devices-alexa-as-media-player-testers-needed/58639 """ from __future__ import annotations from datetime import timedelta from homeassistant.const import ( CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONCENTRATION_PARTS_PER_MILLION, PERCENTAGE, ) PROJECT_URL = "https://github.com/alandtse/alexa_media_player/" ISSUE_URL = f"{PROJECT_URL}issues" NOTIFY_URL = f"{PROJECT_URL}wiki/Configuration%3A-Notification-Component#use-the-notifyalexa_media-service" DOMAIN = "alexa_media" DATA_ALEXAMEDIA = "alexa_media" PLAY_SCAN_INTERVAL = 20 SCAN_INTERVAL = timedelta(seconds=60) MIN_TIME_BETWEEN_SCANS = SCAN_INTERVAL MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1) ALEXA_COMPONENTS = [ "media_player", ] DEPENDENT_ALEXA_COMPONENTS = [ "notify", "switch", "sensor", "alarm_control_panel", "light", "binary_sensor", ] HTTP_COOKIE_HEADER = "# HTTP Cookie File" CONF_ACCOUNTS = "accounts" CONF_DEBUG = "debug" CONF_HASS_URL = "hass_url" CONF_INCLUDE_DEVICES = "include_devices" CONF_EXCLUDE_DEVICES = "exclude_devices" CONF_QUEUE_DELAY = "queue_delay" CONF_PUBLIC_URL = "public_url" CONF_EXTENDED_ENTITY_DISCOVERY = "extended_entity_discovery" CONF_SECURITYCODE = "securitycode" CONF_OTPSECRET = "otp_secret" CONF_PROXY = "proxy" CONF_PROXY_WARNING = "proxy_warning" CONF_SCAN_INTERVAL = ( "scan_interval" # local definition; HA's CONF_SCAN_INTERVAL is deprecated ) CONF_TOTP_REGISTER = "registered" CONF_OAUTH = "oauth" DATA_LISTENER = "listener" EXCEPTION_TEMPLATE = "An exception of type {0} occurred. Arguments:\n{1!r}" DEFAULT_DEBUG = False DEFAULT_EXTENDED_ENTITY_DISCOVERY = False DEFAULT_HASS_URL = "http://homeassistant.local:8123" DEFAULT_PUBLIC_URL = "" DEFAULT_QUEUE_DELAY = 1.5 DEFAULT_SCAN_INTERVAL = 60 EPOCH_MS_THRESHOLD = 10_000_000_000 # Service name constants used by services.py SERVICE_DEFS SERVICE_UPDATE_LAST_CALLED = "update_last_called" SERVICE_RESTORE_VOLUME = "restore_volume" SERVICE_GET_HISTORY_RECORDS = "get_history_records" SERVICE_FORCE_LOGOUT = "force_logout" SERVICE_ENABLE_NETWORK_DISCOVERY = "enable_network_discovery" # Backoff durations for the last-called probe worker LAST_CALLED_429_BACKOFF_INITIAL_S = 30.0 LAST_CALLED_429_BACKOFF_MAX_S = 15 * 60.0 LAST_CALLED_CONN_BACKOFF_S = 10.0 LAST_CALLED_LOGIN_BACKOFF_S = 30.0 # Tuning constants for the per-account last-called probe worker LAST_CALLED_DEBOUNCE_S = 3.5 # coalesce bursty pushes, but stay snappy LAST_CALLED_RETRY_DELAY_S = 4.0 # wider retry cadence for delayed routine history LAST_CALLED_RETRY_LIMIT = 2 # total attempts = 1 + retries (3 attempts) LAST_CALLED_STALE_FUDGE_MS = 5_000 # allow some clock/ordering jitter LAST_CALLED_SUCCESS_PACE_S = 4.0 # post-success pacing to avoid hammering LAST_CALLED_LOOKBACK_MS = 60_000 LAST_CALLED_ITEMS = 10 LAST_CALLED_COALESCE_WINDOW_MS = 2000 # Tuning constants for notification retries NOTIFICATION_COOLDOWN = 60 NOTIFY_REFRESH_BACKOFF = 15.0 NOTIFY_REFRESH_MAX_RETRIES = 3 # push-health magic numbers HTTP2_ERROR_THRESHOLD = 5 LAST_PUSH_INACTIVITY_SECONDS = 600.0 LAST_PING_MAX_AGE_SECONDS = 900.0 RECURRING_PATTERN = { None: "Never Repeat", "P1D": "Every day", "P1M": "Every month", "XXXX-WE": "Weekends", "XXXX-WD": "Weekdays", "XXXX-WXX-1": "Every Monday", "XXXX-WXX-2": "Every Tuesday", "XXXX-WXX-3": "Every Wednesday", "XXXX-WXX-4": "Every Thursday", "XXXX-WXX-5": "Every Friday", "XXXX-WXX-6": "Every Saturday", "XXXX-WXX-7": "Every Sunday", } RECURRING_DAY = { "MO": 1, "TU": 2, "WE": 3, "TH": 4, "FR": 5, "SA": 6, "SU": 7, } RECURRING_PATTERN_ISO_SET = { None: {}, "P1D": {1, 2, 3, 4, 5, 6, 7}, "XXXX-WE": {6, 7}, "XXXX-WD": {1, 2, 3, 4, 5}, "XXXX-WXX-1": {1}, "XXXX-WXX-2": {2}, "XXXX-WXX-3": {3}, "XXXX-WXX-4": {4}, "XXXX-WXX-5": {5}, "XXXX-WXX-6": {6}, "XXXX-WXX-7": {7}, } ATTR_MESSAGE = "message" ATTR_EMAIL = "email" ATTR_ENTITY_ID = "entity_id" ATTR_NUM_ENTRIES = "entries" COMMON_BUCKET_COUNTS = ( "accounts", "devices", "media_players", "players", "notifications", "entities", ) COMMON_DIAGNOSTIC_BUCKETS = ( "account", "accounts", "login", "logins", "session", "sessions", ) COMMON_DIAGNOSTIC_NAMES = ( "name", "deviceName", "accountName", "friendlyName", "title", ) DEVICE_PLAYER_BUCKETS = ("devices", "media_players", "players") TO_REDACT: set[str] = { "email", "password", "access_token", "refresh_token", "token", "csrf", "cookie", "cookies", "session", "sessionid", "macDms", "mac_dms", "otp_secret", "authorization_code", "securitycode", "code_verifier", "adp_token", "device_private_key", "customerId", } STREAMING_ERROR_MESSAGE = ( "Sorry, direct music streaming isn't supported. " "This limitation is set by Amazon, and not by Alexa-Media-Player, Music-Assistant, nor Home-Assistant." ) PUBLIC_URL_ERROR_MESSAGE = ( "To send TTS, please set the public URL in integration configuration." ) STARTUP_MESSAGE = """ {name} Version Info {DOMAIN}: v{version} alexapy API: v{alexapy_version} If you have any issues with this custom component, you need to open an issue here: {ISSUE_URL} """ AUTH_CALLBACK_PATH = "/auth/alexamedia/callback" AUTH_CALLBACK_NAME = "auth:alexamedia:callback" AUTH_PROXY_PATH = "/auth/alexamedia/proxy" AUTH_PROXY_NAME = "auth:alexamedia:proxy" ALEXA_UNIT_CONVERSION = { "Alexa.Unit.Percent": PERCENTAGE, "Alexa.Unit.PartsPerMillion": CONCENTRATION_PARTS_PER_MILLION, "Alexa.Unit.Density.MicroGramsPerCubicMeter": CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, } ALEXA_ICON_CONVERSION = { "Alexa.AirQuality.CarbonMonoxide": "mdi:molecule-co", "Alexa.AirQuality.Humidity": "mdi:water-percent", "Alexa.AirQuality.IndoorAirQuality": "mdi:numeric", "Alexa.AirQuality.ParticulateMatter": "mdi:blur", "Alexa.AirQuality.VolatileOrganicCompounds": "mdi:air-filter", } ALEXA_ICON_DEFAULT = "mdi:molecule" # Device class mapping for air quality sensors # Maps Alexa sensor types to Home Assistant SensorDeviceClass ALEXA_AIR_QUALITY_DEVICE_CLASS = { "Alexa.AirQuality.ParticulateMatter": "pm25", "Alexa.AirQuality.CarbonMonoxide": "carbon_monoxide", "Alexa.AirQuality.IndoorAirQuality": "aqi", "Alexa.AirQuality.VolatileOrganicCompounds": "aqi", "Alexa.AirQuality.Humidity": "humidity", } UPLOAD_PATH = "www/alexa_tts" # Note: Some of these are likely wrong MODEL_IDS = { "A10A33FOX2NUBK": "Echo Spot (Gen1)", "A10L5JEZTKKCZ8": "Vobot Bunny", "A11QM4H9HGV71H": "Echo Show 5 (Gen3)", "A12GXV8XMS007S": "Fire TV (Gen1)", "A12IZU8NMHSY5U": "Generic Device", "A132LT22WVG6X5": "Samsung Soundbar Q700A", "A13B2WB920IZ7X": "Samsung HW-Q70T Soundbar", "A13W6HQIHKEN3Z": "Echo Auto", "A14ZH95E6SE9Z1": "Bose Home Speaker 300", "A15996VY63BQ2D": "Echo Show 8 (Gen2)", "A15ERDAKK5HQQG": "Sonos", "A15QWUTQ6FSMYX": "Echo Buds (Gen2)", "A16MZVIFVHX6P6": "Generic Echo", "A17LGWINFBUTZZ": "Anker Roav Viva", "A18BI6KPKDOEI4": "Ecobee4", "A18O6U1UQFJ0XK": "Echo Plus (Gen2)", "A18TCD9FP10WJ9": "Orbi Voice", "A18X8OBWBCSLD8": "Samsung Soundbar", "A195TXHV1M5D4A": "Echo Auto", "A1C66CX2XD756O": "Fire Tablet HD", "A1D54LQEG0OXJ2": "Denon Home 250", "A1EIANJ7PNB0Q7": "Echo Show 15 (Gen1)", "A1ENT81UXFMNNO": "Unknown", "A1ETW4IXK2PYBP": "Talk to Alexa", "A1F1F76XIW4DHQ": "Unknown TV", "A1F8D55J0FWDTN": "Fire TV (Toshiba)", "A1H0CMF1XM0ZP4": "Bose SoundTouch 30", "A1J16TEDOYCZTN": "Fire Tablet", "A1JJ0KFC4ZPNJ3": "Echo Input", "A1L4KDRIILU6N9": "Sony Speaker", "A1LOQ8ZHF4G510": "Samsung Soundbar Q990B", "A1M0A9L9HDBID3": "One-Link Safe and Sound", "A1MKGHX5VQBDWX": "Denon Home 150", "A1MUORL8FP149X": "Unknown", "A1N9SW0I0LUX5Y": "Ford/Lincoln Alexa App", "A1NL4BVLQ4L3N3": "Echo Show (Gen1)", "A1NQ0LXWBGVQS9": "2021 Samsung QLED TV", "A1P31Q3MOWSHOD": "Zolo Halo Speaker", "A1P7E7V3FCZKU6": "Fire TV (Gen3)", "A1Q69AKRWLJC0F": "TV", "A1Q7QCGNMXAKYW": "Generic Tablet", "A1QKZ9D0IJY332": "Samsung TV 2020-U", "A1RABVCI4QCIKC": "Echo Dot (Gen3)", "A1RTAM01W29CUP": "Windows App", "A1SCI5MODUBAT1": "Pioneer DMH-W466NEX", "A1TD5Z1R8IWBHA": "Tablet", "A1VGB7MHSIEYFK": "Fire TV Cube Gen3", "A1W2YILXTG9HA7": "Nextbase 522GW Dashcam", "A1W46V57KES4B5": "Cable TV box Brazil", "A1WZKXFLI43K86": "Fire TV Stick MAX", "A1XWJRHALS1REP": "Echo Show 5 (Gen2)", "A1Z88NGR2BK6A2": "Echo Show 8 (Gen1)", "A25EC4GIHFOCSG": "Unrecognized Media Player", "A25OJWHZA1MWNB": "2021 Samsung QLED TV", "A265XOI9586NML": "Fire TV Stick", "A27VEYGQBW3YR5": "Echo Link", "A2A3XFQ1AVYLHZ": "SONY WF-1000XM5", "A2BRQDVMSZD13S": "SURE Universal Remote", "A2C8J6UHV0KFCV": "Alexa Gear", "A2DS1Q2TPDJ48U": "Echo Dot Clock (Gen5)", "A2E0SNTXJVT7WK": "Fire TV (Gen2)", "A2E5N6DMWCW8MZ": "Brilliant Smart Switch", "A2EZ3TS0L1S2KV": "Sonos Beam", "A2GFL5ZMWNE0PX": "Fire TV (Gen3)", "A2H4LV5GIZ1JFT": "Echo Dot Clock (Gen4)", "A2HZENIFNYTXZD": "Facebook Portal", "A2I0SCCU3561Y8": "Samsung Soundbar Q800A", "A2IS7199CJBT71": "TV", "A2IVLV5VM2W81": "Alexa Mobile Voice iOS", "A2J0R2SD7G9LPA": "Lenovo SmartTab M10", "A2JKHJ0PX4J3L3": "Fire TV Cube (Gen2)", "A2LH725P8DQR2A": "Fabriq Riff", "A2LLN0UXRW4N50": "Echo Show 11 (Gen1)", "A2LWARUGJLBYEW": "Fire TV Stick (Gen2)", "A2M35JJZWCQOMZ": "Echo Plus (Gen1)", "A2M4YX06LWP8WI": "Fire Tablet", "A2N49KXGVA18AR": "Fire Tablet HD 10 Plus", "A2OSP3UA4VC85F": "Sonos", "A2R2GLZH1DFYQO": "Zolo Halo Speaker", "A2RU4B77X9R9NZ": "Echo Link Amp", "A2TF17PFR55MTB": "Alexa Mobile Voice Android", "A2TTLILJHVNI9X": "LG TV", "A2U21SRK4QGSE1": "Echo Dot (Gen4)", "A2UONLFQW0PADH": "Echo Show 8 (Gen3)", "A2V9UEGZ82H4KZ": "Fire Tablet HD 10", "A2VAXZ7UNGY4ZH": "Wyze Headphones", "A2WFDCBDEXOXR8": "Bose Soundbar 700", "A2WJ2CM9ARLMRH": "Rivian Electric Vehicle", "A2WN1FJ2HG09UN": "Ultimate Alexa App", "A2X8WT9JELC577": "Ecobee5", "A2XPGY5LRKB9BE": "Fitbit Versa 2", "A2Y04QPFCANLPQ": "Bose QuietComfort 35 II", "A303PJF6ISQ7IC": "Echo Auto", "A30YDR2MK8HMRV": "Echo (Gen3)", "A31DTMEEVDDOIV": "Fire TV Stick Lite", "A324YMIUSWQDGE": "Samsung 8K TV", "A32DDESGESSHZA": "Echo Dot (Gen3)", "A32DOYMUN6DTXA": "Echo Dot (Gen3)", "A339L426Y220I4": "Teufel Radio", "A347G2JC8I4HC7": "Roav Car Charger Pro", "A37CFAHI1O0CXT": "Logitech Blast", "A37M7RU8Z6ZFB": "Garmin Speak", "A37SHHQ3NUL7B5": "Bose Home Speaker 500", "A38949IHXHRQ5P": "Echo Tap", "A38BPK7OW001EX": "Raspberry Alexa", "A38EHHIB10L47V": "Fire Tablet HD 8", "A39BU42XNMN516": "Generic Device", "A3B50IC5QPZPWP": "Polk Command Bar", "A3B5K1G3EITBIF": "Facebook Portal", "A3BRT6REMPQWA8": "Bose Home Speaker 450", "A3BW5ZVFHRCQPO": "BMW Alexa Integration", "A3C9PE6TNYLTCH": "Speaker Group", "A3CY98NH016S5F": "Facebook Portal Mini", "A3D4YURNTARP5K": "Facebook Portal TV", "A3EH2E0YZ30OD6": "Echo Spot (Gen2)", "A3EVMLQTU6WL1W": "Fire TV Stick 4K Max (Gen1)", "A3F1S88NTZZXS9": "Dash Wand", "A3FX4UWTP28V1P": "Echo (Gen3)", "A3GFRGUNIGG1I5": "Samsung TV QN50Q60CAGXZD", "A3HF4YRA2L7XGC": "Fire TV Cube", "A3IYPH06PH1HRA": "Echo Frames", "A3K69RS3EIMXPI": "Hisense Smart TV", "A3KULB3NQN7Z1F": "Unknown TV", "A3L0T0VL9A921N": "Fire Tablet HD 8", "A3NPD82ABCPIDP": "Sonos Beam", "A3QPPX1R9W5RJV": "Fabriq Chorus", "A3QS1XP2U6UJX9": "SONY WF-1000XM4", "A3R9S4ZZECZ6YL": "Fire Tablet HD 10", "A3RBAYBE7VM004": "Echo Studio", "A3RCTOK2V0A4ZG": "LG TV", "A3RMGO6LYLH7YN": "Echo Dot (Gen4)", "A3S5BH2HU6VAYF": "Echo Dot (Gen2)", "A3SSG6GR8UU7SN": "Echo Sub", "A3SSWQ04XYPXBH": "Generic Tablet", "A3TCJ8RTT3NVI7": "Alexa Listens", "A3VRME03NAXFUB": "Echo Flex", "A4ZP7ZC4PI6TO": "Echo Show 5 (Gen1)", "A4ZXE0RM7LQ7A": "Echo Dot (Gen5)", "A52ARKF0HM2T4": "Facebook Portal+", "A6SIQKETF3L2E": "Unknown Device", "A7WXQPH584YP": "Echo (Gen2)", "A81PNL0A63P93": "Home Remote", "A8DM4FYR6D3HT": "TV", "AA1IN44SS3X6O": "Ecobee Thermostat Premium", "AB72C64C86AW2": "Echo (Gen1)", "ABJ2EHL7HQT4L": "Unknown Amplifier", "ADVBD696BHNV5": "Fire TV Stick (Gen1)", "AE7X7Z227NFNS": "HiMirror Mini", "AF473ZSOIRKFJ": "Onkyo VC-PX30", "AFF50AL5E3DIU": "Fire TV (Insignia)", "AFF5OAL5E3DIU": "Fire TV", "AGHZIK8D6X7QR": "Fire TV", "AHJYKVA63YCAQ": "Sonos", "AIPK7MM90V7TB": "Echo Show 10 (Gen3)", "AKKLQD9FZWWQS": "Jabra Elite", "AKNO1N0KSFN8L": "Echo Dot (Gen1)", "AKO51L5QAQKL2": "Alexa Jams", "AKPGW064GI9HE": "Fire TV Stick 4K (Gen3)", "ALCIV0P5M8TZ0": "Samsung Soundbar S800B", "ALT9P69K6LORD": "Echo Auto", "AMCZ48H33RCDF": "Samsung HW-Q910B 9.1.2 ch Soundbar", "AN630UQPG2CA4": "Fire TV (Toshiba)", "AO6HHP9UE6EOF": "Unknown Media Device", "AP1F6KUH00XPV": "Stereo/Subwoofer Pair", "AP4RS91ZQ0OOI": "Fire TV (Toshiba)", "APHEAY6LX7T13": "Samsung Smart Refrigerator", "AQCGW9PSYWRF": "TV", "AR6X0XNIME80V": "Unknown TV", "ASQZWP4GPYUT7": "Echo Pop", "ATNLRCEBX3W4P": "Generic Tablet", "AUPUQSVCVHXP0": "Ecobee Switch+", "AVD3HM0HOJAAL": "Sonos", "AVE5HX13UR5NO": "Logitech Zero Touch", "AVN2TMX8MU2YM": "Bose Home Speaker 500", "AVU7CPPF2ZRAS": "Fire Tablet HD 8", "AWZZ5CVHX2CD": "Echo Show (Gen2)", }