├── custom_components └── location_reminders │ ├── const.py │ ├── manifest.json │ └── __init__.py ├── LICENSE ├── README.md └── dist └── location-reminder-card.js /custom_components/location_reminders/const.py: -------------------------------------------------------------------------------- 1 | DOMAIN = 'location_reminders' -------------------------------------------------------------------------------- /custom_components/location_reminders/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "location_reminders", 3 | "name": "Location Reminder", 4 | "documentation": "https://github.com/baruchiro/lovelace-location-reminders", 5 | "issue_tracker": "https://github.com/baruchiro/lovelace-location-reminders/issues", 6 | "version": "0.1", 7 | "requirements": [], 8 | "dependencies": [], 9 | "codeowners": ["@baruchiro"] 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Baruch Odem (Rothkoff) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /custom_components/location_reminders/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from homeassistant.config_entries import ConfigEntry 3 | from homeassistant.core import HomeAssistant 4 | from homeassistant.helpers.typing import ConfigType 5 | from homeassistant.helpers.entity import Entity 6 | from homeassistant.helpers.entity_component import EntityComponent 7 | from homeassistant.const import STATE_UNKNOWN 8 | from .const import DOMAIN 9 | 10 | 11 | _LOGGER = logging.getLogger(__name__) 12 | 13 | async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: 14 | _LOGGER.info("Setting up Location Reminder integration") 15 | hass.data[DOMAIN] = { 16 | "reminders": [], 17 | "zones": [] 18 | } 19 | 20 | async def update_sensor_state(): 21 | _LOGGER.info("Updating sensor state") 22 | reminders = hass.data[DOMAIN]["reminders"] 23 | zones = hass.data[DOMAIN]["zones"] 24 | hass.states.async_set(f'sensor.{DOMAIN}', len(reminders), { 25 | "reminders": reminders, 26 | "zones": zones 27 | }) 28 | 29 | 30 | async def async_update_zones(): 31 | zones = [zone.name for zone in hass.states.async_all() if zone.domain == 'zone'] 32 | hass.data[DOMAIN]['zones'] = zones 33 | await update_sensor_state() 34 | _LOGGER.info(f"Updated zones: {zones}") 35 | 36 | async def handle_add_reminder(call): 37 | _LOGGER.info("Handling add_reminder service call") 38 | reminder = { 39 | "text": call.data.get("text"), 40 | "zone": call.data.get("zone") 41 | } 42 | hass.data[DOMAIN]["reminders"].append(reminder) 43 | await update_sensor_state() 44 | 45 | async def handle_remove_reminder(call): 46 | _LOGGER.info("Handling remove_reminder service call") 47 | index = call.data.get("index") 48 | if 0 <= index < len(hass.data[DOMAIN]["reminders"]): 49 | hass.data[DOMAIN]["reminders"].pop(index) 50 | await update_sensor_state() 51 | 52 | hass.services.async_register(DOMAIN, 'add_reminder', handle_add_reminder) 53 | hass.services.async_register(DOMAIN, 'remove_reminder', handle_remove_reminder) 54 | hass.services.async_register(DOMAIN, 'update_zones', async_update_zones) 55 | 56 | hass.async_create_task(async_update_zones()) 57 | 58 | return True 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Location Reminders 2 | 3 | 4 | [![License](https://img.shields.io/github/license/baruchiro/lovelace-location-reminders.svg)](LICENSE) 5 | 6 | Location Reminders is a custom integration for Home Assistant that allows you to set reminders based on your location. This integration is available through the Home Assistant Community Store (HACS) and includes a dashboard plugin (custom card) for easy management. 7 | 8 | ## Installation 9 | 10 | ### HACS (Home Assistant Community Store) 11 | 12 | 1. Ensure that HACS is installed and configured in your Home Assistant instance. 13 | 2. Go to the HACS panel in Home Assistant. 14 | 3. Click on "Integrations". 15 | 4. Search for "Location Reminders". 16 | 5. Click "Install". 17 | 18 | ### Manual Installation 19 | 20 | 1. Download the latest release from the [GitHub releases page](https://github.com/baruchiro/lovelace-location-reminders/releases). 21 | 2. Extract the downloaded archive. 22 | 3. Copy the `custom_components/location_reminders` directory to your Home Assistant `custom_components` directory. 23 | 24 | ## Configuration 25 | 26 | 1. Add the following to your `configuration.yaml` file: 27 | 28 | ```yaml 29 | location_reminders: 30 | ``` 31 | 32 | 2. Restart Home Assistant. 33 | 34 | ## Usage 35 | 36 | ### Dashboard Plugin (Custom Card) 37 | 38 | This integration includes a custom Lovelace card for managing location-based reminders directly from the Home Assistant dashboard. 39 | 40 | #### Adding the Custom Card 41 | 42 | 1. Go to your Home Assistant Lovelace dashboard. 43 | 2. Click on the three dots menu (⋮) in the top right corner and select "Edit Dashboard". 44 | 3. Click on "Add Card". 45 | 4. Search for "Location Reminders" and select it. 46 | 5. Configure the card as needed and click "Save". 47 | 48 | #### Example Configuration 49 | 50 | ```yaml 51 | type: custom:location-reminders-card 52 | title: Location Reminders 53 | ``` 54 | 55 | ## Services 56 | 57 | In addition to the dashboard plugin, this integration provides the following services: 58 | 59 | - `location_reminders.add_reminder`: Add a new reminder. 60 | - `location_reminders.remove_reminder`: Remove an existing reminder. 61 | - `location_reminders.update_zones`: Update the list of zones. 62 | 63 | #### Example Service Call 64 | 65 | To add a reminder, use the following service call: 66 | 67 | ```yaml 68 | service: location_reminders.add_reminder 69 | data: 70 | text: "Buy groceries" 71 | zone: "home" 72 | ``` 73 | 74 | To remove a reminder, use the following service call: 75 | 76 | ```yaml 77 | service: location_reminders.remove_reminder 78 | data: 79 | index: 0 80 | ``` 81 | 82 | To update the list of zones, use the following service call: 83 | 84 | ```yaml 85 | service: location_reminders.update_zones 86 | ``` 87 | 88 | ## License 89 | 90 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 91 | 92 | ## Support 93 | 94 | For issues and feature requests, please use the GitHub issue tracker. 95 | 96 | -------------------------------------------------------------------------------- /dist/location-reminder-card.js: -------------------------------------------------------------------------------- 1 | class LocationReminderCard extends HTMLElement { 2 | set hass(hass) { 3 | let root = this.shadowRoot; 4 | if (!root) { 5 | this.attachShadow({ mode: 'open' }); 6 | root = this.shadowRoot; 7 | } 8 | 9 | const reminders = hass.states['sensor.location_reminders']?.attributes.reminders || []; 10 | const zones = hass.states['sensor.location_reminders']?.attributes.zones || []; 11 | 12 | root.innerHTML = ` 13 | 14 |
15 | ${reminders.map((reminder, index) => ` 16 |
17 | ${reminder.text} - ${reminder.zone} 18 | 19 |
20 | `).join('')} 21 |
22 | 23 | 28 | 29 |
30 |
31 |
32 | `; 33 | 34 | root.querySelector('#add').onclick = async () => { 35 | const text = root.querySelector('#text').value; 36 | const zone = root.querySelector('#zone').value; 37 | 38 | // Send data to the backend 39 | await hass.callService('location_reminders', 'add_reminder', { text, zone }).catch(console.error); 40 | 41 | // Update the list of reminders dynamically 42 | const reminderList = root.querySelector('.card-content'); 43 | const listItem = document.createElement('div'); 44 | listItem.innerHTML = ` 45 | ${text} - ${zone} 46 | 47 | `; 48 | reminderList.insertBefore(listItem, reminderList.lastElementChild); 49 | 50 | // Clear the form fields 51 | root.querySelector('#text').value = ''; 52 | root.querySelector('#zone').value = ''; 53 | 54 | // Re-attach remove event listener to the new button 55 | listItem.querySelector('.remove').onclick = (e) => { 56 | const index = e.target.dataset.index; 57 | hass.callService('location_reminders', 'remove_reminder', { index }); 58 | }; 59 | }; 60 | 61 | root.querySelectorAll('.remove').forEach(button => { 62 | button.onclick = (e) => { 63 | const index = e.target.dataset.index; 64 | hass.callService('location_reminders', 'remove_reminder', { index }); 65 | }; 66 | }); 67 | } 68 | 69 | setConfig(config) { 70 | // Configuration options (if any) 71 | } 72 | 73 | getCardSize() { 74 | return 3; 75 | } 76 | } 77 | 78 | customElements.define('location-reminder-card', LocationReminderCard); --------------------------------------------------------------------------------