diff --git a/__init__.py b/__init__.py index d951d07..2d6855a 100644 --- a/__init__.py +++ b/__init__.py @@ -2,28 +2,39 @@ import asyncio import logging from datetime import datetime, timedelta +import voluptuous as vol from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.helpers.typing import ConfigType +import homeassistant.helpers.config_validation as cv from .const import DOMAIN -from .coordinator import MedMateDataUpdateCoordinator _LOGGER = logging.getLogger(__name__) PLATFORMS = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.BUTTON] +# Configuration schema - this tells HA what config keys are allowed +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({}) +}, extra=vol.ALLOW_EXTRA) + async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up MedMate integration.""" + # Initialize the domain data storage + hass.data.setdefault(DOMAIN, {}) return True async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up MedMate from a config entry.""" try: + # Import coordinator here to avoid circular imports + from .coordinator import MedMateDataUpdateCoordinator + coordinator = MedMateDataUpdateCoordinator(hass, entry) await coordinator.async_config_entry_first_refresh() @@ -33,6 +44,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + # Set up update listener for options changes + entry.async_on_unload(entry.add_update_listener(async_update_options)) + return True except Exception as err: _LOGGER.error("Error setting up MedMate integration: %s", err) @@ -42,8 +56,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" try: - if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): - hass.data[DOMAIN].pop(entry.entry_id) + unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) + + if unload_ok: + hass.data[DOMAIN].pop(entry.entry_id, None) return unload_ok except Exception as err: @@ -54,4 +70,9 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: """Reload config entry.""" await async_unload_entry(hass, entry) - await async_setup_entry(hass, entry) \ No newline at end of file + await async_setup_entry(hass, entry) + + +async def async_update_options(hass: HomeAssistant, config_entry: ConfigEntry) -> None: + """Handle options update.""" + await hass.config_entries.async_reload(config_entry.entry_id) \ No newline at end of file diff --git a/config_flow.py b/config_flow.py index 6ec35e2..ac3dd91 100644 --- a/config_flow.py +++ b/config_flow.py @@ -11,6 +11,7 @@ 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, @@ -102,26 +103,39 @@ class MedMateConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) -> FlowResult: """Handle schedule configuration.""" if user_input is not None: + # Process the checkbox inputs + selected_days = [] + selected_times = [] + + # Process days + for day in DAYS_OF_WEEK: + if user_input.get(f"day_{day}", False): + selected_days.append(day) + + # Process times + for time_key in TIME_SLOTS.keys(): + if user_input.get(f"time_{time_key}", False): + selected_times.append(time_key) + self._schedule_data = { - CONF_DAYS: user_input.get(CONF_DAYS, []), - CONF_TIMES: user_input.get(CONF_TIMES, []) + CONF_DAYS: selected_days, + CONF_TIMES: selected_times } return await self.async_step_prescription() - # Create day options dict - day_options = {} + # Create schema with individual checkboxes + schema_dict = {} + + # Add day checkboxes (default all days selected) for day in DAYS_OF_WEEK: - day_options[day] = day.title() + schema_dict[vol.Optional(f"day_{day}", default=True)] = bool + + # 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 - # Create time options dict - time_options = {} - for key, value in TIME_SLOTS.items(): - time_options[key] = value - - schema = vol.Schema({ - vol.Required(CONF_DAYS, default=DAYS_OF_WEEK): cv.multi_select(day_options), - vol.Required(CONF_TIMES, default=["morning"]): cv.multi_select(time_options), - }) + schema = vol.Schema(schema_dict) return self.async_show_form( step_id="schedule", @@ -259,34 +273,44 @@ class MedMateOptionsFlow(config_entries.OptionsFlow): medicine_id = self.config_entry.data.get("medicine_id") current_medicine = medicines.get(medicine_id, {}) current_schedule = current_medicine.get(CONF_SCHEDULE, {}) + current_days = current_schedule.get(CONF_DAYS, DAYS_OF_WEEK) + current_times = current_schedule.get(CONF_TIMES, ["morning"]) if user_input is not None: + # Process the checkbox inputs + selected_days = [] + selected_times = [] + + # Process days + for day in DAYS_OF_WEEK: + if user_input.get(f"day_{day}", False): + selected_days.append(day) + + # Process times + for time_key in TIME_SLOTS.keys(): + if user_input.get(f"time_{time_key}", False): + selected_times.append(time_key) + self._schedule_data = { - CONF_DAYS: user_input.get(CONF_DAYS, []), - CONF_TIMES: user_input.get(CONF_TIMES, []) + CONF_DAYS: selected_days, + CONF_TIMES: selected_times } return await self.async_step_prescription() - # Create day options dict - day_options = {} + # Create schema with individual checkboxes + schema_dict = {} + + # Add day checkboxes with current values as defaults for day in DAYS_OF_WEEK: - day_options[day] = day.title() + default_val = day in current_days + schema_dict[vol.Optional(f"day_{day}", default=default_val)] = bool + + # Add time checkboxes with current values as defaults + for time_key, time_label in TIME_SLOTS.items(): + default_val = time_key in current_times + schema_dict[vol.Optional(f"time_{time_key}", default=default_val)] = bool - # Create time options dict - time_options = {} - for key, value in TIME_SLOTS.items(): - time_options[key] = value - - schema = vol.Schema({ - vol.Required( - CONF_DAYS, - default=current_schedule.get(CONF_DAYS, DAYS_OF_WEEK) - ): cv.multi_select(day_options), - vol.Required( - CONF_TIMES, - default=current_schedule.get(CONF_TIMES, ["morning"]) - ): cv.multi_select(time_options), - }) + schema = vol.Schema(schema_dict) return self.async_show_form( step_id="schedule", diff --git a/strings.json b/strings.json index 6bf7536..f176d38 100644 --- a/strings.json +++ b/strings.json @@ -18,10 +18,20 @@ }, "schedule": { "title": "Dosing Schedule", - "description": "Configure when you take this medicine.", + "description": "Select when you take this medicine.", "data": { - "days": "Days of the Week", - "times": "Times of Day" + "day_monday": "Monday", + "day_tuesday": "Tuesday", + "day_wednesday": "Wednesday", + "day_thursday": "Thursday", + "day_friday": "Friday", + "day_saturday": "Saturday", + "day_sunday": "Sunday", + "time_morning": "Morning (8:00 AM)", + "time_lunchtime": "Lunchtime (12:00 PM)", + "time_dinner": "Dinner (6:00 PM)", + "time_night": "Night (10:00 PM)", + "time_custom": "Custom Time" } }, "prescription": { @@ -59,8 +69,18 @@ "title": "Update Dosing Schedule", "description": "Update when you take this medicine.", "data": { - "days": "Days of the Week", - "times": "Times of Day" + "day_monday": "Monday", + "day_tuesday": "Tuesday", + "day_wednesday": "Wednesday", + "day_thursday": "Thursday", + "day_friday": "Friday", + "day_saturday": "Saturday", + "day_sunday": "Sunday", + "time_morning": "Morning (8:00 AM)", + "time_lunchtime": "Lunchtime (12:00 PM)", + "time_dinner": "Dinner (6:00 PM)", + "time_night": "Night (10:00 PM)", + "time_custom": "Custom Time" } }, "prescription": { diff --git a/translations/en.json b/translations/en.json new file mode 100644 index 0000000..86c23f5 --- /dev/null +++ b/translations/en.json @@ -0,0 +1,105 @@ +{ + "config": { + "step": { + "user": { + "title": "MedMate - Medicine Tracker", + "description": "Set up a new medicine to track with MedMate.", + "data": {} + }, + "medicine_basic": { + "title": "Medicine Information", + "description": "Enter the basic information about your medicine.", + "data": { + "medicine_name": "Medicine Name", + "active_ingredient": "Active Ingredient", + "strength": "Strength (optional)", + "pack_size": "Pack Size (pills per pack)" + } + }, + "schedule": { + "title": "Dosing Schedule", + "description": "Configure when you take this medicine.", + "data": { + "days": "Days of the Week", + "times": "Times of Day" + }, + "data_description": { + "days": "Select which days of the week you take this medicine", + "times": "Select the times of day when you take this medicine" + } + }, + "prescription": { + "title": "Prescription Details", + "description": "Enter prescription information to track repeats and expiry.", + "data": { + "issue_date": "Issue Date", + "expiry_date": "Expiry Date", + "doctor": "Doctor (optional)", + "total_repeats": "Total Repeats", + "repeats_left": "Repeats Left (optional)" + } + } + }, + "error": { + "name_exists": "A medicine with this name already exists" + }, + "abort": { + "already_configured": "Medicine is already configured" + } + }, + "options": { + "step": { + "medicine_basic": { + "title": "Update Medicine Information", + "description": "Update the basic information about your medicine.", + "data": { + "medicine_name": "Medicine Name", + "active_ingredient": "Active Ingredient", + "strength": "Strength (optional)", + "pack_size": "Pack Size (pills per pack)" + } + }, + "schedule": { + "title": "Update Dosing Schedule", + "description": "Update when you take this medicine.", + "data": { + "days": "Days of the Week", + "times": "Times of Day" + } + }, + "prescription": { + "title": "Update Prescription Details", + "description": "Update prescription information.", + "data": { + "issue_date": "Issue Date", + "expiry_date": "Expiry Date", + "doctor": "Doctor (optional)", + "total_repeats": "Total Repeats", + "repeats_left": "Repeats Left" + } + } + } + }, + "selector": { + "days": { + "options": { + "monday": "Monday", + "tuesday": "Tuesday", + "wednesday": "Wednesday", + "thursday": "Thursday", + "friday": "Friday", + "saturday": "Saturday", + "sunday": "Sunday" + } + }, + "times": { + "options": { + "morning": "Morning", + "lunchtime": "Lunchtime", + "dinner": "Dinner", + "night": "Night", + "custom": "Custom" + } + } + } +} \ No newline at end of file