All notable changes to this project are documented in this file. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
Maintenance release on top of 2.0.2: the integration no longer trips Home
Assistant's blocking call detector while setting up.
- Blocking call in the event loop.
curl_cffiwas imported lazily insidecreate_transport(), which runs duringasync_setup_entry()and therefore inside the event loop. Importing it reads package metadata throughimportlib.metadata, which scanssite-packages(listdir), so every start-up loggedDetected blocking call to listdir ... custom_components/timetree/api.py, line 94. The transport libraries are now imported at module level - Home Assistant loads integration modules in the executor - andcreate_transport()imports nothing. - Building the HTTP session (which loads a native TLS library) no longer happens in
the event loop. The client is created through the new
TimeTreeApi.async_create()factory, which constructs it in the executor; all three call sites (setup, config flow, options flow) use it. api.pyimporteduuidinside_login()andexport.pyimportedasyncioinside a helper; both imports moved to module level and the helper was removed.
- Version bumped to
2.0.3inmanifest.jsonand in the README version badge. - Four regression tests covering the module level imports, the transport fallback, the
executor based construction and the absence of inline
TimeTreeApi(...)call sites.
Brand and maintenance release on top of 2.0.1. It brings the new brand artwork
derived from the project banner and two export fixes.
- New brand images in
custom_components/timetree/brand/, derived from the project banner:icon.png/icon@2x.pngcarry the TimeTree wordmark, andlogo.png/logo@2x.pngplusdark_logo.png/dark_logo@2x.pngcarry the full banner. All six files keep their Home Assistant sizes (icon 256/512, logo shortest side 256/512). - The project banner (
ha_timetree.jpg) is shown at the top of the README. - Export attendee filter — the export can be restricted to events that include at least one of the selected members. The member list is discovered dynamically from the calendars, and a separate switch decides whether events without any attendee are exported as well.
newest_winsis now applied toboth_changedconflicts instead of leaving them queued indefinitely.- Unmanaged-import fingerprints no longer raise a false conflict on every poll once the initial import has settled.
- Version bumped to
2.0.2inmanifest.jsonand in the README version badge. - Repository housekeeping: the stale
ha2026_09_devbranch was removed, somainis again the only branch.
- Automatic two-way deletion synchronisation: deleting an exported copy now also
removes the TimeTree event (and the other way round) under the
newest_winsandtarget_winspolicies.
- Recurring events are no longer duplicated on export; only the occurrences that actually overlap the export window are written.
- Switching the export target no longer reports every event as
target_removed— the sync record is reset when the target entity changes. - Occurrences of a recurring series are recognised as in-sync (summary, description and location are normalised) instead of being reported as modified.
- A sync record that already has a target fingerprint but no target uid yet (Google Calendar expanding a series) counts as exported, and the resulting duplicate-copy errors are no longer logged.
First stable release of the 2.0.x line. It promotes the two pre-releases
(2.0.0-beta.1, 2.0.0-beta.2) to a normal release and comes with the license
change and the final documentation pass. There are no functional changes to the
integration compared to 2.0.0-beta.2.
- A second version badge and a license badge in the README.
- License: the project is now released under the GNU General Public License
v3.0 (
GPL-3.0-only) instead of MIT. The full text is inLICENSE; the README,info.mdand this changelog were updated accordingly. - Version bumped to
2.0.0inmanifest.jsonand in the README version badge (previously2.0.0-beta.2). hacs.jsonkeepshomeassistant: 2026.9.0, so the minimum required Home Assistant version is unchanged.
- Multi calendar support, complete event import, create/update/delete write
support, the export/sync loop to other calendar entities and the full conflict
management workflow (
2.0.0-beta.1). - The restructured wiki — documentation home, Architecture Design Document,
Software Design Document, Workflow Diagrams — plus the archived 1.1.3 design
documentation (
2.0.0-beta.2).
See the 2.0.0-beta.1 and 2.0.0-beta.2 sections below for the detailed,
per-change lists.
Documentation release. The integration code is unchanged from 2.0.0-beta.1; this
release ships the restructured wiki and the updated project documentation so that the
released archive contains the same documents as the branch.
- Wiki restructure: a documentation home that routes between the current 2.0.x line and the archived 1.1.3 line, an Architecture Design Document (14 decisions, requirements, deltas, risks), a Software Design Document (modules, contracts, data model, error matrix, traceability) and Workflow Diagrams (GitDiagram repository map plus the authored 2.0.x flows; the page also records the verified limitation that GitDiagram can only index the repository default branch).
- The former Developer & Technical Reference Guide is preserved as archived design documentation with a list of the defects fixed in 2.0.x.
- README and
info.mdlink the design documents; the manifestdocumentationkey now points at the wiki.
Complete rework of the integration: multi calendar support, real write support, an export loop to other calendars and conflict management.
- Multiple calendars per account — the setup flow lets you select any number of TimeTree calendars; each one becomes its own calendar entity and device, and the options flow can add or remove calendars later.
- Write support for
calendar.create_event,calendar.update_eventandcalendar.delete_event(used by the WebSocket API, scripts and automations). - Export loop (
custom_components/timetree/export.py): mirrors TimeTree events into any calendar entity (for example a Google Calendar), with a selectable interval (5–1440 min), export window (past/future days),export_onlyortwo_waydirection, dry-run mode, optional deletion of copies of removed events, optional recreation of deleted copies and optional import of events that only exist in the target. - Export markers — exported copies carry
[timetree:<uuid>]in their description so they can be matched reliably on every run; the copy is created before a superseded version is removed, so a failed write never loses data. - Conflict management: a persisted sync snapshot, a decision table
(
conflicts.py), a conflict policy (manual,source_wins,target_wins,newest_wins), pending conflicts in theSync conflictssensor, a persistent notification, thetimetree_conflict_detectedevent and the servicestimetree.list_conflicts,timetree.resolve_conflictandtimetree.resolve_all_conflictswith the resolutionsuse_timetree,use_export_target,use_newest,skipandignore_forever. - New services:
timetree.refresh_now,timetree.export_now,timetree.get_event(plus the conflict services above). - New entities: a calendar entity per TimeTree calendar, Last updated (per calendar), Sync conflicts, Last export and Export status sensors.
- Recurrence expansion (
recurrence.py): recurring events are expanded into single occurrences for a queried range usingdateutil, with support forEXDATE,RDATE,COUNT,UNTILand all-day series. Non standard rules (lunar) fall back to the stored occurrence instead of breaking a view. - Richer event data: labels (with colours), attendees, location coordinates, event URLs, optional event comments, memos; labels and attendees can be added to the description.
- Diagnostics with credentials, e-mail and passwords redacted.
- Brand images ship inside
custom_components/timetree/brand/(icon, logo and dark logo, 1x and 2x). - Events on the Home Assistant event bus:
timetree_export_completedandtimetree_conflict_detected. - A local test harness (
tests/) with 41 tests / 224 checks that runs without a Home Assistant installation.
- Recurring events no longer break the calendar (
#2,#7): theRRULE:prefix is stripped before handing a rule to Home Assistant, rules are validated and occurrences are expanded per requested range, so month and week views load. calendar.create_eventworks (#3,#5): the entity reads thedtstart/dtendkeys that Home Assistant core normalises the service data into (the oldstart_date_time/start_datekeys never existed), accepts the WebSocket spelling as well and is covered by tests for both.- All-day events are no longer off by one (
#5) in either direction: TimeTree's inclusive end becomes Home Assistant's exclusive end on read, and the exclusive end becomes inclusive on write. All-day timestamps are written as UTC midnights, which is what the TimeTree web client does. - Writes are accepted by TimeTree (
#5): the singular/api/v1/calendar/{id}/eventresource is used, the payload carrieslabel_id,attendees,attachment.virtual_user_attendees,recurrencesandalerts, a freshX-CSRF-Tokenis scraped from the event editor page and browser shaped headers plus a browser TLS fingerprint (curl_cffi,impersonate="firefox135") are used. - TimeTree API error handling:
-702(temporarily blocked login) and other rejections produce a readable message instead of a generic "unknown error"; expired sessions are re-authenticated transparently. - Negative timestamps (events before 1970) are converted with integer
arithmetic instead of
datetime.fromtimestamp, which raises on some platforms. - Complete event import: the
events/synccursor is followed untilchunkisfalseinstead of stopping after the first page. - Home Assistant 2026.9 compatibility:
entry.runtime_datainstead ofhass.data,ConfigFlowResult, anOptionsFlowwithout a custom__init__taking the entry, device registry deprecations (via_device_idinstead ofvia_device,async_get_or_createviaDeviceInfo) andAddConfigEntryEntitiesCallback. - Manifest cleanup: the unused
icalendarrequirement was dropped,curl_cffiwas added,integration_type,issue_trackerandloggerswere added and the minimum Home Assistant version is now explicit.
- The integration is now a hub style integration: one config entry holds the account (e-mail/password) and the list of selected calendars.
- Options moved into a menu based options flow (calendars, polling/events, export, conflicts) instead of a single interval slider.
- Entities use the shared coordinator data model (
TimeTreeData), device registry devices per calendar and a stableunique_idderived from the config entry and the TimeTree calendar id. - The scan interval range was extended to 5–1440 minutes.
- Old 1.x config entries are picked up automatically (single calendar layout,
legacy
calendar_id/calendar_namekeys). - Documentation: the README was rewritten,
info.mdand this changelog were added.
- The
icalendardependency (never used) and the duplicated parsing helpers. hass.data[DOMAIN]storage; everything lives on the config entry now.
- Home Assistant 2026.9 is the new minimum version.
curl_cffiis installed as a requirement of the integration. Reading works without it, writing may be rejected by TimeTree's anti bot layer.- Nothing is written to a second calendar until the export loop is enabled in the
options; the default is disabled with the
manualconflict policy.
- 1.1.3 – last release of the 1.x series (single calendar, read plus create, polling interval slider).
- 1.0.1 – earlier 1.x release.