From a7259bca0882554ce2d57d8f1da67ff3c07544fd Mon Sep 17 00:00:00 2001 From: dematheson Date: Sun, 17 Aug 2025 23:02:10 +1000 Subject: [PATCH] Fix set up issue AGAIN --- __init__.py | 7 +- binary_sensor.py | 20 ++++-- button.py | 31 +++++--- config_flow.py | 131 +++++++++++++++++++++++----------- coordinator.py | 77 +++++++++++++++++--- sensor.py | 91 ++++++++++++++++++----- services.yaml => services.yml | 0 7 files changed, 270 insertions(+), 87 deletions(-) rename services.yaml => services.yml (100%) diff --git a/__init__.py b/__init__.py index 2d6855a..22d2212 100644 --- a/__init__.py +++ b/__init__.py @@ -14,11 +14,14 @@ from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -PLATFORMS = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.BUTTON] +# Temporarily test with only sensors +PLATFORMS = [Platform.SENSOR] +# PLATFORMS = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.BUTTON] # Configuration schema - this tells HA what config keys are allowed +# Since this is a config_flow integration, we don't expect any YAML config CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({}) + DOMAIN: vol.Schema({}, extra=vol.PREVENT_EXTRA) }, extra=vol.ALLOW_EXTRA) diff --git a/binary_sensor.py b/binary_sensor.py index 62495a8..e64eb74 100644 --- a/binary_sensor.py +++ b/binary_sensor.py @@ -114,7 +114,8 @@ class MedMateDoseDueSensor(MedMateBaseBinarySensor): next_dose = datetime.fromisoformat(next_dose) except ValueError: next_dose = None - attrs["next_dose"] = next_dose + if next_dose: + attrs["next_dose"] = next_dose return attrs @@ -146,10 +147,18 @@ class MedMatePrescriptionActiveSensor(MedMateBaseBinarySensor): data = self.coordinator.data prescription = data.get(CONF_PRESCRIPTION, {}) - return { - "expiry_date": prescription.get(CONF_EXPIRY_DATE), - "repeats_left": prescription.get(CONF_REPEATS_LEFT, 0), - } + # Only return expected keys + attrs = {} + + expiry_date = prescription.get(CONF_EXPIRY_DATE) + if expiry_date: + attrs["expiry_date"] = expiry_date + + repeats_left = prescription.get(CONF_REPEATS_LEFT) + if repeats_left is not None: + attrs["repeats_left"] = repeats_left + + return attrs class MedMateLowInventorySensor(MedMateBaseBinarySensor): @@ -176,7 +185,6 @@ class MedMateLowInventorySensor(MedMateBaseBinarySensor): inventory = data.get("inventory", 0) # Consider inventory low if less than 7 doses remain - # This assumes daily medication - could be made configurable return inventory < 7 @property diff --git a/button.py b/button.py index e55ceba..f8d1b3e 100644 --- a/button.py +++ b/button.py @@ -30,19 +30,32 @@ async def async_setup_entry( """Set up MedMate buttons.""" coordinator = hass.data[DOMAIN][config_entry.entry_id] + # Wait for first update to ensure we have clean data + if not coordinator.data: + await coordinator.async_request_refresh() + buttons = [ MedMateFillPrescriptionButton(coordinator, config_entry), ] - # Add take dose buttons for each scheduled time - schedule = coordinator.data.get(CONF_SCHEDULE, {}) - scheduled_times = schedule.get(CONF_TIMES, []) - - for time_slot in scheduled_times: - if time_slot in TIME_SLOTS: - buttons.append( - MedMateTakeDoseButton(coordinator, config_entry, time_slot) - ) + # Safely get scheduled times with error handling + try: + schedule = coordinator.data.get(CONF_SCHEDULE, {}) + scheduled_times = schedule.get(CONF_TIMES, []) if isinstance(schedule, dict) else [] + + # Validate that scheduled_times is a list and contains expected values + if isinstance(scheduled_times, list): + for time_slot in scheduled_times: + if isinstance(time_slot, str) and time_slot in TIME_SLOTS: + buttons.append( + MedMateTakeDoseButton(coordinator, config_entry, time_slot) + ) + else: + _LOGGER.warning("Invalid scheduled_times format: %s", type(scheduled_times)) + + except Exception as err: + _LOGGER.error("Error setting up dose buttons: %s", err) + # Continue with just the fill prescription button async_add_entities(buttons) diff --git a/config_flow.py b/config_flow.py index ac3dd91..67abf59 100644 --- a/config_flow.py +++ b/config_flow.py @@ -1,4 +1,4 @@ -"""Config flow for MedMate integration.""" +"""Config flow for MedMate integration - Bulletproof version.""" from __future__ import annotations import logging @@ -11,7 +11,6 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers import config_validation as cv from homeassistant.helpers.storage import Store -from homeassistant.helpers import selector from .const import ( DOMAIN, @@ -82,13 +81,19 @@ class MedMateConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if medicine_name in medicines and self._editing_medicine_id != medicine_name: errors[CONF_MEDICINE_NAME] = "name_exists" else: - self._medicine_data = user_input + # Store ONLY the expected keys - CRITICAL FILTERING + self._medicine_data = { + CONF_MEDICINE_NAME: user_input[CONF_MEDICINE_NAME], + CONF_ACTIVE_INGREDIENT: user_input[CONF_ACTIVE_INGREDIENT], + CONF_STRENGTH: user_input.get(CONF_STRENGTH, ""), + CONF_PACK_SIZE: user_input.get(CONF_PACK_SIZE, DEFAULT_PACK_SIZE), + } return await self.async_step_schedule() schema = vol.Schema({ - vol.Required(CONF_MEDICINE_NAME): str, - vol.Required(CONF_ACTIVE_INGREDIENT): str, - vol.Optional(CONF_STRENGTH, default=""): str, + vol.Required(CONF_MEDICINE_NAME): cv.string, + vol.Required(CONF_ACTIVE_INGREDIENT): cv.string, + vol.Optional(CONF_STRENGTH, default=""): cv.string, vol.Optional(CONF_PACK_SIZE, default=DEFAULT_PACK_SIZE): cv.positive_int, }) @@ -103,39 +108,45 @@ class MedMateConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) -> FlowResult: """Handle schedule configuration.""" if user_input is not None: - # Process the checkbox inputs + # CRITICAL: Extract only the actual values, ignore ALL form keys selected_days = [] selected_times = [] - # Process days + # Process days - extract values from checkbox form keys for day in DAYS_OF_WEEK: - if user_input.get(f"day_{day}", False): + form_key = f"day_{day}" + if user_input.get(form_key, False): selected_days.append(day) - # Process times + # Process times - extract values from checkbox form keys for time_key in TIME_SLOTS.keys(): - if user_input.get(f"time_{time_key}", False): + form_key = f"time_{time_key}" + if user_input.get(form_key, False): selected_times.append(time_key) + # Store ONLY the clean, expected data structure self._schedule_data = { CONF_DAYS: selected_days, CONF_TIMES: selected_times } + + _LOGGER.debug("Processed schedule data: %s", self._schedule_data) return await self.async_step_prescription() - # Create schema with individual checkboxes - schema_dict = {} + # Create form schema with temporary checkbox keys + # These keys are ONLY for the form, never stored permanently + schema_fields = {} - # Add day checkboxes (default all days selected) + # Add day checkboxes (all selected by default) for day in DAYS_OF_WEEK: - schema_dict[vol.Optional(f"day_{day}", default=True)] = bool + schema_fields[vol.Optional(f"day_{day}", default=True)] = cv.boolean - # Add time checkboxes (default morning selected) - for time_key, time_label in TIME_SLOTS.items(): - default_val = time_key == "morning" # Only morning selected by default - schema_dict[vol.Optional(f"time_{time_key}", default=default_val)] = bool + # Add time checkboxes (only morning selected by default) + for time_key in TIME_SLOTS.keys(): + default_val = (time_key == "morning") + schema_fields[vol.Optional(f"time_{time_key}", default=default_val)] = cv.boolean - schema = vol.Schema(schema_dict) + schema = vol.Schema(schema_fields) return self.async_show_form( step_id="schedule", @@ -147,7 +158,14 @@ class MedMateConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) -> FlowResult: """Handle prescription information.""" if user_input is not None: - self._prescription_data = user_input + # Store ONLY expected prescription keys + self._prescription_data = { + CONF_ISSUE_DATE: user_input.get(CONF_ISSUE_DATE), + CONF_EXPIRY_DATE: user_input.get(CONF_EXPIRY_DATE), + CONF_DOCTOR: user_input.get(CONF_DOCTOR, ""), + CONF_TOTAL_REPEATS: user_input.get(CONF_TOTAL_REPEATS, DEFAULT_REPEATS), + CONF_REPEATS_LEFT: user_input.get(CONF_REPEATS_LEFT), + } return await self.async_create_entry_data() today = date.today() @@ -156,7 +174,7 @@ class MedMateConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): schema = vol.Schema({ vol.Optional(CONF_ISSUE_DATE, default=today): cv.date, vol.Optional(CONF_EXPIRY_DATE, default=expiry_date): cv.date, - vol.Optional(CONF_DOCTOR, default=""): str, + vol.Optional(CONF_DOCTOR, default=""): cv.string, vol.Optional(CONF_TOTAL_REPEATS, default=DEFAULT_REPEATS): cv.positive_int, vol.Optional(CONF_REPEATS_LEFT): cv.positive_int, }) @@ -169,18 +187,22 @@ class MedMateConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def async_create_entry_data(self) -> FlowResult: """Create the config entry.""" # Set repeats_left to total_repeats if not specified - if CONF_REPEATS_LEFT not in self._prescription_data: + if not self._prescription_data.get(CONF_REPEATS_LEFT): self._prescription_data[CONF_REPEATS_LEFT] = self._prescription_data[CONF_TOTAL_REPEATS] + # Build the complete medicine data with ONLY expected keys medicine_data = { - **self._medicine_data, - CONF_SCHEDULE: self._schedule_data, + CONF_MEDICINE_NAME: self._medicine_data[CONF_MEDICINE_NAME], + CONF_ACTIVE_INGREDIENT: self._medicine_data[CONF_ACTIVE_INGREDIENT], + CONF_STRENGTH: self._medicine_data[CONF_STRENGTH], + CONF_PACK_SIZE: self._medicine_data[CONF_PACK_SIZE], + CONF_SCHEDULE: self._schedule_data, # Contains only CONF_DAYS and CONF_TIMES CONF_PRESCRIPTION: self._prescription_data, "inventory": 0, "last_taken": {}, } - # Store the medicine data + # Store the medicine data in the persistent storage store = Store(self.hass, STORAGE_VERSION, STORAGE_KEY) existing_data = await store.async_load() or {} medicines = existing_data.get("medicines", {}) @@ -190,9 +212,17 @@ class MedMateConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): await store.async_save({"medicines": medicines}) + # Create config entry with MINIMAL data - only what Home Assistant needs + # CRITICAL: Only store the medicine_id, nothing else that could cause validation issues + config_entry_data = { + "medicine_id": medicine_id + } + + _LOGGER.debug("Creating config entry with data: %s", config_entry_data) + return self.async_create_entry( title=f"MedMate - {self._medicine_data[CONF_MEDICINE_NAME]}", - data={"medicine_id": medicine_id}, + data=config_entry_data, # Only the minimal required data ) @staticmethod @@ -234,22 +264,28 @@ class MedMateOptionsFlow(config_entries.OptionsFlow): current_medicine = medicines.get(medicine_id, {}) if user_input is not None: - self._medicine_data = user_input + # Filter to only expected keys + self._medicine_data = { + CONF_MEDICINE_NAME: user_input[CONF_MEDICINE_NAME], + CONF_ACTIVE_INGREDIENT: user_input[CONF_ACTIVE_INGREDIENT], + CONF_STRENGTH: user_input.get(CONF_STRENGTH, ""), + CONF_PACK_SIZE: user_input.get(CONF_PACK_SIZE, DEFAULT_PACK_SIZE), + } return await self.async_step_schedule() schema = vol.Schema({ vol.Required( CONF_MEDICINE_NAME, default=current_medicine.get(CONF_MEDICINE_NAME, "") - ): str, + ): cv.string, vol.Required( CONF_ACTIVE_INGREDIENT, default=current_medicine.get(CONF_ACTIVE_INGREDIENT, "") - ): str, + ): cv.string, vol.Optional( CONF_STRENGTH, default=current_medicine.get(CONF_STRENGTH, "") - ): str, + ): cv.string, vol.Optional( CONF_PACK_SIZE, default=current_medicine.get(CONF_PACK_SIZE, DEFAULT_PACK_SIZE) @@ -277,7 +313,7 @@ class MedMateOptionsFlow(config_entries.OptionsFlow): current_times = current_schedule.get(CONF_TIMES, ["morning"]) if user_input is not None: - # Process the checkbox inputs + # Extract clean values from form checkboxes selected_days = [] selected_times = [] @@ -291,26 +327,27 @@ class MedMateOptionsFlow(config_entries.OptionsFlow): if user_input.get(f"time_{time_key}", False): selected_times.append(time_key) + # Store only clean data self._schedule_data = { CONF_DAYS: selected_days, CONF_TIMES: selected_times } return await self.async_step_prescription() - # Create schema with individual checkboxes - schema_dict = {} + # Create form schema with checkboxes + schema_fields = {} # Add day checkboxes with current values as defaults for day in DAYS_OF_WEEK: default_val = day in current_days - schema_dict[vol.Optional(f"day_{day}", default=default_val)] = bool + schema_fields[vol.Optional(f"day_{day}", default=default_val)] = cv.boolean # Add time checkboxes with current values as defaults - for time_key, time_label in TIME_SLOTS.items(): + for time_key in TIME_SLOTS.keys(): default_val = time_key in current_times - schema_dict[vol.Optional(f"time_{time_key}", default=default_val)] = bool + schema_fields[vol.Optional(f"time_{time_key}", default=default_val)] = cv.boolean - schema = vol.Schema(schema_dict) + schema = vol.Schema(schema_fields) return self.async_show_form( step_id="schedule", @@ -330,7 +367,14 @@ class MedMateOptionsFlow(config_entries.OptionsFlow): current_prescription = current_medicine.get(CONF_PRESCRIPTION, {}) if user_input is not None: - self._prescription_data = user_input + # Filter to expected prescription keys only + self._prescription_data = { + CONF_ISSUE_DATE: user_input.get(CONF_ISSUE_DATE), + CONF_EXPIRY_DATE: user_input.get(CONF_EXPIRY_DATE), + CONF_DOCTOR: user_input.get(CONF_DOCTOR, ""), + CONF_TOTAL_REPEATS: user_input.get(CONF_TOTAL_REPEATS, DEFAULT_REPEATS), + CONF_REPEATS_LEFT: user_input.get(CONF_REPEATS_LEFT, DEFAULT_REPEATS), + } return await self.async_update_entry_data() today = date.today() @@ -347,7 +391,7 @@ class MedMateOptionsFlow(config_entries.OptionsFlow): vol.Optional( CONF_DOCTOR, default=current_prescription.get(CONF_DOCTOR, "") - ): str, + ): cv.string, vol.Optional( CONF_TOTAL_REPEATS, default=current_prescription.get(CONF_TOTAL_REPEATS, DEFAULT_REPEATS) @@ -373,10 +417,13 @@ class MedMateOptionsFlow(config_entries.OptionsFlow): medicine_id = self.config_entry.data.get("medicine_id") current_medicine = medicines.get(medicine_id, {}) - # Update medicine data + # Update with only expected keys updated_medicine = { **current_medicine, - **self._medicine_data, + CONF_MEDICINE_NAME: self._medicine_data[CONF_MEDICINE_NAME], + CONF_ACTIVE_INGREDIENT: self._medicine_data[CONF_ACTIVE_INGREDIENT], + CONF_STRENGTH: self._medicine_data[CONF_STRENGTH], + CONF_PACK_SIZE: self._medicine_data[CONF_PACK_SIZE], CONF_SCHEDULE: self._schedule_data, CONF_PRESCRIPTION: self._prescription_data, } diff --git a/coordinator.py b/coordinator.py index dbf49c2..6060e31 100644 --- a/coordinator.py +++ b/coordinator.py @@ -14,12 +14,19 @@ from .const import ( DOMAIN, STORAGE_KEY, STORAGE_VERSION, + CONF_MEDICINE_NAME, + CONF_ACTIVE_INGREDIENT, + CONF_STRENGTH, + CONF_PACK_SIZE, CONF_SCHEDULE, CONF_PRESCRIPTION, CONF_DAYS, CONF_TIMES, CONF_EXPIRY_DATE, CONF_REPEATS_LEFT, + CONF_ISSUE_DATE, + CONF_DOCTOR, + CONF_TOTAL_REPEATS, TIME_SLOTS, ) @@ -62,10 +69,59 @@ class MedMateDataUpdateCoordinator(DataUpdateCoordinator): medicine_data = medicines[self.medicine_id] - # Calculate derived values - medicine_data = self._calculate_derived_data(medicine_data) + # Clean the data to ensure no unwanted keys are present + cleaned_data = self._clean_medicine_data(medicine_data) - return medicine_data + # Calculate derived values + cleaned_data = self._calculate_derived_data(cleaned_data) + + return cleaned_data + + def _clean_medicine_data(self, medicine_data: dict[str, Any]) -> dict[str, Any]: + """Clean medicine data to remove any unwanted keys from config flow.""" + if not medicine_data: + return {} + + # Define the expected structure + cleaned = {} + + # Basic medicine info + for key in [CONF_MEDICINE_NAME, CONF_ACTIVE_INGREDIENT, CONF_STRENGTH, CONF_PACK_SIZE]: + if key in medicine_data: + cleaned[key] = medicine_data[key] + + # Clean schedule data + schedule = medicine_data.get(CONF_SCHEDULE, {}) + if isinstance(schedule, dict): + cleaned_schedule = {} + + # Only include expected schedule keys + if CONF_DAYS in schedule and isinstance(schedule[CONF_DAYS], list): + cleaned_schedule[CONF_DAYS] = schedule[CONF_DAYS] + if CONF_TIMES in schedule and isinstance(schedule[CONF_TIMES], list): + cleaned_schedule[CONF_TIMES] = schedule[CONF_TIMES] + + cleaned[CONF_SCHEDULE] = cleaned_schedule + + # Clean prescription data + prescription = medicine_data.get(CONF_PRESCRIPTION, {}) + if isinstance(prescription, dict): + cleaned_prescription = {} + + # Only include expected prescription keys + for key in [CONF_ISSUE_DATE, CONF_EXPIRY_DATE, CONF_DOCTOR, CONF_TOTAL_REPEATS, CONF_REPEATS_LEFT]: + if key in prescription: + cleaned_prescription[key] = prescription[key] + + cleaned[CONF_PRESCRIPTION] = cleaned_prescription + + # Include other expected keys + for key in ["inventory", "last_taken"]: + if key in medicine_data: + cleaned[key] = medicine_data[key] + + _LOGGER.debug("Cleaned medicine data: %s", cleaned) + return cleaned def _calculate_derived_data(self, medicine_data: dict[str, Any]) -> dict[str, Any]: """Calculate derived data for the medicine.""" @@ -100,7 +156,7 @@ class MedMateDataUpdateCoordinator(DataUpdateCoordinator): days = schedule.get(CONF_DAYS, []) times = schedule.get(CONF_TIMES, []) - if not days or not times: + if not days or not times or not isinstance(days, list) or not isinstance(times, list): return None # Get current day of week (0=Monday, 6=Sunday) @@ -114,7 +170,10 @@ class MedMateDataUpdateCoordinator(DataUpdateCoordinator): "friday": 4, "saturday": 5, "sunday": 6 } - scheduled_weekdays = [weekday_map[day] for day in days if day in weekday_map] + scheduled_weekdays = [] + for day in days: + if isinstance(day, str) and day in weekday_map: + scheduled_weekdays.append(weekday_map[day]) if not scheduled_weekdays: return None @@ -122,7 +181,7 @@ class MedMateDataUpdateCoordinator(DataUpdateCoordinator): # Get dose times for today and future dose_times = [] for time_slot in times: - if time_slot in DEFAULT_TIMES: + if isinstance(time_slot, str) and time_slot in DEFAULT_TIMES: dose_times.append(DEFAULT_TIMES[time_slot]) if not dose_times: @@ -156,7 +215,7 @@ class MedMateDataUpdateCoordinator(DataUpdateCoordinator): times = schedule.get(CONF_TIMES, []) last_taken = medicine_data.get("last_taken", {}) - if not days or not times: + if not days or not times or not isinstance(days, list) or not isinstance(times, list): return False current_weekday = now.strftime("%A").lower() @@ -168,7 +227,7 @@ class MedMateDataUpdateCoordinator(DataUpdateCoordinator): # Check each scheduled time slot for time_slot in times: - if time_slot not in DEFAULT_TIMES: + if not isinstance(time_slot, str) or time_slot not in DEFAULT_TIMES: continue slot_time = DEFAULT_TIMES[time_slot] @@ -243,7 +302,7 @@ class MedMateDataUpdateCoordinator(DataUpdateCoordinator): prescription[CONF_REPEATS_LEFT] = repeats_left - 1 # Add to inventory - pack_size = medicine_data.get("pack_size", 30) + pack_size = medicine_data.get(CONF_PACK_SIZE, 30) current_inventory = medicine_data.get("inventory", 0) medicine_data["inventory"] = current_inventory + pack_size diff --git a/sensor.py b/sensor.py index a680a6a..868297c 100644 --- a/sensor.py +++ b/sensor.py @@ -24,6 +24,8 @@ from .const import ( CONF_PACK_SIZE, CONF_SCHEDULE, CONF_PRESCRIPTION, + CONF_DAYS, + CONF_TIMES, CONF_ISSUE_DATE, CONF_EXPIRY_DATE, CONF_DOCTOR, @@ -101,6 +103,43 @@ class MedMateBaseSensor(CoordinatorEntity, SensorEntity): """Return if entity is available.""" return self.coordinator.last_update_success and bool(self.coordinator.data) + def _get_clean_schedule_attributes(self, schedule_data: dict) -> dict[str, Any]: + """Extract only valid schedule attributes, filtering out form keys.""" + if not schedule_data: + return {} + + clean_schedule = {} + + # Only include expected schedule keys + if CONF_DAYS in schedule_data: + clean_schedule[CONF_DAYS] = schedule_data[CONF_DAYS] + if CONF_TIMES in schedule_data: + clean_schedule[CONF_TIMES] = schedule_data[CONF_TIMES] + + return clean_schedule + + def _get_clean_prescription_attributes(self, prescription_data: dict) -> dict[str, Any]: + """Extract only valid prescription attributes.""" + if not prescription_data: + return {} + + clean_attrs = {} + + # Only include expected prescription keys + expected_keys = [ + CONF_ISSUE_DATE, + CONF_EXPIRY_DATE, + CONF_DOCTOR, + CONF_TOTAL_REPEATS, + CONF_REPEATS_LEFT, + ] + + for key in expected_keys: + if key in prescription_data: + clean_attrs[f"prescription_{key}"] = prescription_data[key] + + return clean_attrs + class MedMateInventorySensor(MedMateBaseSensor): """Sensor for medicine inventory.""" @@ -132,23 +171,23 @@ class MedMateInventorySensor(MedMateBaseSensor): schedule = data.get(CONF_SCHEDULE, {}) prescription = data.get(CONF_PRESCRIPTION, {}) + # Build clean attributes - CRITICAL: Only include expected keys attrs = { ATTR_ACTIVE_INGREDIENT: data.get(CONF_ACTIVE_INGREDIENT), ATTR_STRENGTH: data.get(CONF_STRENGTH), ATTR_PACK_SIZE: data.get(CONF_PACK_SIZE), - ATTR_SCHEDULE: schedule, ATTR_PRESCRIPTION_ACTIVE: data.get("prescription_active", False), } - # Add prescription details if available - if prescription: - attrs.update({ - ATTR_ISSUE_DATE: prescription.get(CONF_ISSUE_DATE), - ATTR_EXPIRY_DATE: prescription.get(CONF_EXPIRY_DATE), - ATTR_DOCTOR: prescription.get(CONF_DOCTOR), - ATTR_TOTAL_REPEATS: prescription.get(CONF_TOTAL_REPEATS), - ATTR_REPEATS_LEFT: prescription.get(CONF_REPEATS_LEFT), - }) + # Add clean schedule data + clean_schedule = self._get_clean_schedule_attributes(schedule) + if clean_schedule: + attrs["schedule_days"] = clean_schedule.get(CONF_DAYS, []) + attrs["schedule_times"] = clean_schedule.get(CONF_TIMES, []) + + # Add clean prescription details + clean_prescription = self._get_clean_prescription_attributes(prescription) + attrs.update(clean_prescription) return attrs @@ -183,13 +222,16 @@ class MedMateRepeatsSensor(MedMateBaseSensor): data = self.coordinator.data prescription = data.get(CONF_PRESCRIPTION, {}) - return { - ATTR_TOTAL_REPEATS: prescription.get(CONF_TOTAL_REPEATS, 0), + # Only include expected attributes + attrs = { ATTR_PRESCRIPTION_ACTIVE: data.get("prescription_active", False), - ATTR_ISSUE_DATE: prescription.get(CONF_ISSUE_DATE), - ATTR_EXPIRY_DATE: prescription.get(CONF_EXPIRY_DATE), - ATTR_DOCTOR: prescription.get(CONF_DOCTOR), } + + # Add clean prescription data + clean_prescription = self._get_clean_prescription_attributes(prescription) + attrs.update(clean_prescription) + + return attrs class MedMateNextDoseSensor(MedMateBaseSensor): @@ -237,8 +279,19 @@ class MedMateNextDoseSensor(MedMateBaseSensor): except (ValueError, TypeError): most_recent_dose = None - return { - ATTR_SCHEDULE: schedule, - ATTR_LAST_TAKEN: most_recent_dose, + # Build clean attributes + attrs = { "dose_due": data.get("dose_due", False), - } \ No newline at end of file + } + + # Add clean schedule data + clean_schedule = self._get_clean_schedule_attributes(schedule) + if clean_schedule: + attrs["schedule_days"] = clean_schedule.get(CONF_DAYS, []) + attrs["schedule_times"] = clean_schedule.get(CONF_TIMES, []) + + # Add last taken info + if most_recent_dose: + attrs[ATTR_LAST_TAKEN] = most_recent_dose + + return attrs \ No newline at end of file diff --git a/services.yaml b/services.yml similarity index 100% rename from services.yaml rename to services.yml