commit 7e9d5f94a2137cdb3074957d1b3e8c4f9450ffde Author: Brian Nelson Date: Wed Nov 26 11:38:01 2025 -0500 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..1beafb0 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Home Assistant Digital Calendar +This repo is intended to provide some additional help when setting up a digital calendar view for an alternative to a popular digital calendar. The original thread can be found [here](https://community.home-assistant.io/t/diy-family-calendar-skylight/844830) + +## Calendar Connection +It's important to choose a calendar that supports CalDAV. For the sake of this repo I'll be using NextCloud's calendar option as I already have NextCloud running and want to stay away from Google services. + +To connect you calendar you'll need to add the CalDAV integration to your Home Assistant +- Navigate to Settings > Devices & services +- Click add integration +- Search for CalDAV +- Enter your information + - For nextcloud users it's something like: `https://[YOUR_NEXTCLOUD_URL].com/remote.php/dav` (you can also find it in the nextcloud calendar settings > Copy pirmary CalDAV address) + - The username and password of the user you want to add the calendar for + diff --git a/config-2.yaml b/config-2.yaml new file mode 100644 index 0000000..4326f6f --- /dev/null +++ b/config-2.yaml @@ -0,0 +1,426 @@ +views: + - title: Home + sections: + - type: grid + cards: + - square: false + type: grid + cards: + - type: custom:better-moment-card + parentStyle: | + line-height:normal; + moment: + - parentStyle: | + font-size:1em; text-align:center; margin-top:5px; + templateRaw: | + {{moment format=cccc}} + - parentStyle: | + font-size:1.5em; text-align:center; margin-top:5px; + templateRaw: | + {{moment format=LLLL dd, yyyy}} + - parentStyle: | + font-size:4em; text-align:center; font-weight:400; + templateRaw: | + {{moment format=hh:mm}} + card_mod: + style: | + ha-card { + background: transparent !important; + box-shadow: none !important; + border: none !important; + } + - type: custom:weather-card + entity: weather.forecast_home + current: true + details: true + forecast: false + - type: weather-forecast + entity: weather.forecast_home + show_current: false + show_forecast: true + forecast_type: daily + name: Weather Forecast + card_mod: + style: | + ha-card { + background: transparent !important; + box-shadow: none !important; + border: none !important; + } + grid_options: + columns: full + column_span: 4 + - type: grid + cards: + - type: horizontal-stack + cards: + - type: custom:bubble-card + card_type: button + button_type: state + entity: person.brian + scrolling_effect: false + show_icon: true + show_name: true + show_state: false + tap_action: + action: perform-action + perform_action: script.brian_calendar_visible_filter + target: {} + button_action: + tap_action: + action: perform-action + perform_action: script.brian_calendar_visible_filter + target: {} + styles: | + .bubble-button-background { + opacity: 1 !important; + background-color: ${hass.states['input_text.brian_calendar_filter'].state === '.*' ? 'light-grey' : 'rgba(15, 208, 184, 0.3)'} !important;} + } + - type: custom:bubble-card + card_type: button + button_type: state + entity: person.brian + name: Dogs + scrolling_effect: false + show_icon: true + show_name: true + show_state: false + tap_action: + action: perform-action + perform_action: script.dog_calendar_visible_filter + target: {} + button_action: + tap_action: + action: perform-action + perform_action: script.dog_calendar_visible_filter + target: {} + styles: | + .bubble-button-background { + opacity: 1 !important; + background-color: ${hass.states['input_text.dog_calendar_filter'].state === '.*' ? 'light-grey' : 'rgba(15, 100, 255, 0.5)'} !important;} + } + - type: custom:bubble-card + card_type: button + button_type: name + card_layout: large + name: Add Event + icon: mdi:calendar-plus + tap_action: + action: navigate + navigation_path: '#addcalendarevent' + button_action: + tap_action: + action: navigate + navigation_path: '#addcalendarevent' + styles: | + * { + font-size: 1.05em !important; + } + ha-card { + --bubble-main-background-color: #393745 !important; + width: 300px; + } + .bubble-icon { + --mdc-icon-size: 30px !important; + color: snow !important; + opacity: 1; + } + .bubble-icon-container { + background: #393745 !important; + display: flex; + + } + .bubble-name { + color: snow !important; + opacity: 1; + display: flex; + line-height: 18px; + flex-direction: row; + justify-content: center; + flex-grow: 1; + margin: 0 40px 0 0; + pointer-events: none; + position: relative; + overflow: hidden; + } + - type: custom:bubble-card + card_type: select + entity: input_select.calendar_view + show_name: true + show_state: true + name: Select View + show_last_changed: false + show_attribute: false + grid_options: + columns: full + - type: custom:config-template-card + entities: + - input_text.brian_calendar_filter + - input_text.dog_calendar_filter + - inpup_select.calendar_view + variables: + PERSONCAL: states['input_text.brian_calendar_filter']?.state + DOGCAL: states['input_text.dog_calendar_filter']?.state + VIEW: states['input_select.calendar_view']?.state + DAYS: | + (() => { + const calendarView = states['input_select.calendar_view']?.state; + + if (calendarView === 'Today') return 1; + if (calendarView === 'Tomorrow') return 2; + + // Check for Month, Biweek, or Week based on screen width + if (calendarView === 'Week') return 7; + if (calendarView === 'Biweek') return 14; + if (calendarView === 'Month') return 28; + if (calendarView === 'Bimonth') return 56; + + // Default fallback to 7 if no condition matches + return 31; + })() + #### OPTION TO MAKE 1 MONTH VIEW 31 DAYS #### + card: + type: custom:week-planner-card + calendars: + - entity: calendar.personal + name: brian + color: rgba(15, 208, 184, 0.3) + filter: ${ PERSONCAL } + - entity: calendar.dogs + name: dogs + color: rgba(15, 100, 255, 0.5) + filter: ${ DOGCAL } + days: ${ DAYS } + startingDayOffset: 0 + startingDay: month + hideWeekend: false + noCardBackground: false + compact: false + weather: + showCondition: true + showTemperature: true + showLowTemperature: true + useTwiceDaily: false + entity: weather.forecast_home + locale: en + timeFormat: hh:mm + showLocation: false + hidePastEvents: false + hideDaysWithoutEvents: false + hideTodayWithoutEvents: false + combineSimilarEvents: true + showLegend: false + legendToggle: false + texts: + monday: Mon + tuesday: Tue + wednesday: Wed + thursday: Thu + friday: Fri + saturday: Sat + sunday: Sun + yesterday: '' + today: '' + tomorrow: '' + overmorrow: '' + fullDay: '' + noEvents: '' + card_mod: + style: | + ha-card { + #font-family: 'Ovo'; + .container .navigation .data-year { + position: static; + right: 60px; + } + .event.past { + opacity: .2; + background-color: gray !important; + } + .container .data-week { + display: none !important; + } + .time { + color: #333333 !important; + font-size: 0.8em !important; + } + .event { + color: #333333 !important; + line-height: 16px !important; + background-color: var(--border-color) !important; + border-radius: 10px !important; + max-height: 100px !important; + overflow: hidden !important; + font-size: 1.1em !important; + } + .none { + background-color: transparent !important; + } + .today .number { + border-radius: 5px; + background-color: orange !important; + padding-left: 4px; + padding-right: 4px; + } + #.today { + # border: solid 2px #000000 !important; + #} + .day .date .text { + font-size: 1em !important; + font-weight: bold !important; + } + .day .date .number { + font-weight: bold !important; + font-size: 3em !important; + } + .day { + border-radius: 5px; + --background-color: red; + border: solid 1px whitesmoke; + display: flex !important; + flex-direction: column !important; + justify-content: flex-start !important; + align-items: stretch !important; + min-height: 15px !important; + width: 100% !important; + padding: 0 !important; + overflow: hidden !important; + } + .day .event { + white-space: normal !important; + word-break: break-word !important; + } + .container { + display: grid !important; + grid-template-columns: repeat(7, 1fr) !important; + grid-template-rows: auto !important; + gap: 8px !important; + padding: 0px !important; + } + + .container .header, + .container .legend { + grid-column: 1 / -1 !important; /* span full width */ + grid-row: 1 !important; + justify-content: center !important; + } + + .navigation { + display: flex !important; + flex-direction: row !important; + align-items: center !important; + margin-bottom: 0px !important; + text-align: center !important; + } + + .navigation .month { + color: transparent !important; /* hide original text */ + position: relative !important; + white-space: nowrap !important; + align-items: center !important; + } + + .navigation .month::after { + content: "November 🦃" !important; /* new text */ + color: #000000 !important; /* your desired color */ + position: absolute !important; + white-space: nowrap !important; + left: 0; + top: 0; + padding-right: 4px; + } + + /* Reorder days so Sunday is first column */ + .day[data-weekday="1"] { grid-column: 2 !important; } /* Monday */ + .day[data-weekday="2"] { grid-column: 3 !important; } /* Tuesday */ + .day[data-weekday="3"] { grid-column: 4 !important; } /* Wednesday */ + .day[data-weekday="4"] { grid-column: 5 !important; } /* Thursday */ + .day[data-weekday="5"] { grid-column: 6 !important; } /* Friday */ + .day[data-weekday="6"] { grid-column: 7 !important; } /* Saturday */ + .day[data-weekday="7"] { grid-column: 1 !important; } /* Sunday */ + } + .week.past-week { + display: none !important; + } + grid_options: + columns: full + - type: vertical-stack + cards: + - type: custom:bubble-card + card_type: pop-up + hash: '#addcalendarevent' + button_type: name + name: Add Calendar Event + icon: mdi:calendar-plus + scrolling_effect: false + show_icon: true + show_name: true + styles: | + .bubble-button-card-container { + background: + ${hass.states['input_select.calendar_select'].state == + 'brian' ? 'rgba(15, 208, 184, 0.3)' + : hass.states['input_select.calendar_select'].state == + 'dogs' ? 'rgba(15, 100, 255, 0.5)' + : hass.states['input_select.calendar_select'].state == + 'Birthdays' ? '#000000' + : 'red'} !important; + } + modules: [] + - type: vertical-stack + cards: + - type: entities + entities: + - entity: input_select.calendar_select + - entity: input_text.calendar_event_title + name: Event Title + - entity: input_text.calendar_event_description + name: Event Description + - entity: input_boolean.calendar_all_day_event + name: All Day Event + title: Add Calendar Event + state_color: false + - type: conditional + conditions: + - entity: input_boolean.calendar_all_day_event + state: 'off' + card: + type: entities + entities: + - entity: input_datetime.calendar_event_start + name: Start Time + - entity: input_datetime.calendar_event_end + name: End Time + - type: conditional + conditions: + - entity: input_boolean.calendar_all_day_event + state: 'on' + card: + type: entities + entities: + - entity: input_datetime.calendar_day_event_start + name: Event Start Date + - entity: input_datetime.calendar_day_event_end + name: Event End Date + - type: custom:button-card + name: Add Event to Calendar + tap_action: + action: call-service + service: script.add_calendar_event + styles: + card: + - background-color: | + [[[ + if (states['input_select.calendar_select'].state == 'brian') + return "rgba(15, 208, 184, 0.3)"; + if (states['input_select.calendar_select'].state == 'dogs') + return "rgba(15, 100, 255, 0.5)"; + if (states['input_select.calendar_select'].state == 'Birthdays') + return "#33a02c"; + return "gray"; + ]]] + column_span: 4 + header: + layout: center + badges_position: bottom + badges_wrap: scroll diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..657be93 --- /dev/null +++ b/config.yaml @@ -0,0 +1,354 @@ +views: + - title: Home + sections: + - type: grid + cards: + - square: false + type: grid + cards: + - type: custom:better-moment-card + parentStyle: | + line-height:normal; + moment: + - parentStyle: | + font-size:1em; text-align:center; margin-top:5px; + templateRaw: | + {{moment format=cccc}} + - parentStyle: | + font-size:1.5em; text-align:center; margin-top:5px; + templateRaw: | + {{moment format=LLLL dd, yyyy}} + - parentStyle: | + font-size:4em; text-align:center; font-weight:400; + templateRaw: | + {{moment format=hh:mm}} + card_mod: + style: | + ha-card { + background: transparent !important; + box-shadow: none !important; + border: none !important; + } + - type: custom:weather-card + entity: weather.forecast_home + current: true + details: true + forecast: false + - type: weather-forecast + entity: weather.forecast_home + show_current: false + show_forecast: true + forecast_type: daily + name: Weather Forecast + card_mod: + style: | + ha-card { + background: transparent !important; + box-shadow: none !important; + border: none !important; + } + grid_options: + columns: full + column_span: 4 + - type: grid + cards: + - type: horizontal-stack + cards: + - type: custom:bubble-card + card_type: button + button_type: state + entity: person.brian + scrolling_effect: false + show_icon: true + show_name: true + show_state: false + tap_action: + action: perform-action + perform_action: script.brian_calendar_visible_filter + target: {} + button_action: + tap_action: + action: perform-action + perform_action: script.brian_calendar_visible_filter + target: {} + styles: | + .bubble-button-background { + opacity: 1 !important; + background-color: ${hass.states['input_text.brian_calendar_filter'].state === '.*' ? 'light-grey' : 'rgba(15, 208, 184, 0.3)'} !important;} + } + - type: custom:bubble-card + card_type: button + button_type: state + entity: person.brian + name: Dogs + scrolling_effect: false + show_icon: true + show_name: true + show_state: false + tap_action: + action: perform-action + perform_action: script.dog_calendar_visible_filter + target: {} + button_action: + tap_action: + action: perform-action + perform_action: script.dog_calendar_visible_filter + target: {} + styles: | + .bubble-button-background { + opacity: 1 !important; + background-color: ${hass.states['input_text.dog_calendar_filter'].state === '.*' ? 'light-grey' : 'rgba(15, 100, 255, 0.5)'} !important;} + } + - type: custom:bubble-card + card_type: button + button_type: name + card_layout: large + name: Add Event + icon: mdi:calendar-plus + tap_action: + action: navigate + navigation_path: '#addcalendarevent' + button_action: + tap_action: + action: navigate + navigation_path: '#addcalendarevent' + styles: | + * { + font-size: 1.05em !important; + } + ha-card { + --bubble-main-background-color: #393745 !important; + width: 300px; + } + .bubble-icon { + --mdc-icon-size: 30px !important; + color: snow !important; + opacity: 1; + } + .bubble-icon-container { + background: #393745 !important; + display: flex; + + } + .bubble-name { + color: snow !important; + opacity: 1; + display: flex; + line-height: 18px; + flex-direction: row; + justify-content: center; + flex-grow: 1; + margin: 0 40px 0 0; + pointer-events: none; + position: relative; + overflow: hidden; + } + - type: custom:bubble-card + card_type: select + entity: input_select.calendar_view + show_name: true + show_state: true + name: Select View + show_last_changed: false + show_attribute: false + grid_options: + columns: full + - type: custom:config-template-card + entities: + - input_text.brian_calendar_filter + - input_text.dog_calendar_filter + - inpup_select.calendar_view + variables: + PERSONCAL: states['input_text.brian_calendar_filter']?.state + DOGCAL: states['input_text.dog_calendar_filter']?.state + VIEW: states['input_select.calendar_view']?.state + DAYS: | + (() => { + const calendarView = states['input_select.calendar_view']?.state; + + if (calendarView === 'Today') return 1; + if (calendarView === 'Tomorrow') return 2; + + // Check for Month, Biweek, or Week based on screen width + if (calendarView === 'Week') return 7; + if (calendarView === 'Biweek') return 14; + if (calendarView === 'Month') return 28; + if (calendarView === 'Bimonth') return 56; + + // Default fallback to 7 if no condition matches + return 28; + })() + card: + type: custom:week-planner-card + calendars: + - entity: calendar.personal + name: brian + color: rgba(15, 208, 184, 0.3) + filter: ${ PERSONCAL } + - entity: calendar.dogs + name: dogs + color: rgba(15, 100, 255, 0.5) + filter: ${ DOGCAL } + days: ${ DAYS } + startingDayOffset: 0 + startingDay: sunday + hideWeekend: false + noCardBackground: false + compact: false + weather: + showCondition: true + showTemperature: true + showLowTemperature: true + useTwiceDaily: false + entity: weather.forecast_home + locale: en + timeFormat: hh:mm + showLocation: false + hidePastEvents: false + hideDaysWithoutEvents: false + hideTodayWithoutEvents: false + combineSimilarEvents: true + showLegend: false + legendToggle: false + texts: + monday: Mon + tuesday: Tue + wednesday: Wed + thursday: Thu + friday: Fri + saturday: Sat + sunday: Sun + yesterday: '' + today: '' + tomorrow: '' + card_mod: + style: | + ha-card { + .event.past { + opacity: .2; + background-color: gray !important; + } + .time { + color: #333333 !important; + font-size: 0.8em !important; + } + .event { + color: #333333 !important; + line-height: 16px !important; + background-color: var(--border-color) !important; + border-radius: 10px !important; + max-height: 80px !important; + overflow: hidden !important; + font-size: 1.1em !important; + } + .none { + background-color: transparent !important; + } + .today .number { + border-radius: 5px; + background-color: orange !important; + padding-left: 4px; + padding-right: 4px; + + } + .day .date .text { + font-size: 1em !important; + font-weight: bold !important; + } + .day .date .number { + font-weight: bold !important; + font-size: 3em !important; + } + .day { + border-radius: 8px; + --background-color: red; + border: solid 1px whitesmoke; + padding: 0.2%; + width: 13% !important; + } + + + + } + grid_options: + columns: full + - type: vertical-stack + cards: + - type: custom:bubble-card + card_type: pop-up + hash: '#addcalendarevent' + button_type: name + name: Add Calendar Event + icon: mdi:calendar-plus + scrolling_effect: false + show_icon: true + show_name: true + styles: | + .bubble-button-card-container { + background: + ${hass.states['input_select.calendar_select'].state == + 'brian' ? 'rgba(15, 208, 184, 0.3)' + : hass.states['input_select.calendar_select'].state == + 'dogs' ? 'rgba(15, 100, 255, 0.5)' + : hass.states['input_select.calendar_select'].state == + 'Birthdays' ? '#000000' + : 'red'} !important; + } + modules: [] + - type: vertical-stack + cards: + - type: entities + entities: + - entity: input_select.calendar_select + - entity: input_text.calendar_event_title + name: Event Title + - entity: input_text.calendar_event_description + name: Event Description + - entity: input_boolean.calendar_all_day_event + name: All Day Event + title: Add Calendar Event + state_color: false + - type: conditional + conditions: + - entity: input_boolean.calendar_all_day_event + state: 'off' + card: + type: entities + entities: + - entity: input_datetime.calendar_event_start + name: Start Time + - entity: input_datetime.calendar_event_end + name: End Time + - type: conditional + conditions: + - entity: input_boolean.calendar_all_day_event + state: 'on' + card: + type: entities + entities: + - entity: input_datetime.calendar_day_event_start + name: Event Start Date + - entity: input_datetime.calendar_day_event_end + name: Event End Date + - type: custom:button-card + name: Add Event to Calendar + tap_action: + action: call-service + service: script.add_calendar_event + styles: + card: + - background-color: | + [[[ + if (states['input_select.calendar_select'].state == 'brian') + return "rgba(15, 208, 184, 0.3)"; + if (states['input_select.calendar_select'].state == 'dogs') + return "rgba(15, 100, 255, 0.5)"; + if (states['input_select.calendar_select'].state == 'Birthdays') + return "#33a02c"; + return "gray"; + ]]] + column_span: 4 + header: + layout: center + badges_position: bottom + badges_wrap: scroll