Skip to content

Developer Guide

wallenium edited this page Aug 1, 2026 · 1 revision

Developer Guide

Architecture overview

The integration follows a straightforward data flow:

const.pymodel.pysensor.py → Lovelace cards

  • const.py centralizes domain names, storage keys, service constants, and shared attribute names.
  • model.py holds the cycle calculation logic and normalized model generation.
  • sensor.py exposes Home Assistant sensor state and attributes for dashboards and automations.
  • __init__.py wires the integration together, registers services, serves frontend resources, and handles setup/teardown.
  • www/*.js renders the frontend cards based on the sensor attributes.

File structure and why each file exists

Path Purpose
custom_components/menstruation_cycle/__init__.py Integration setup, service registration, resource registration
custom_components/menstruation_cycle/config_flow.py UI-based setup flow
custom_components/menstruation_cycle/const.py Shared constants and public contract keys
custom_components/menstruation_cycle/model.py Domain logic for cycle calculations
custom_components/menstruation_cycle/sensor.py Sensor entity implementation
custom_components/menstruation_cycle/storage.py Persistent storage and normalization
custom_components/menstruation_cycle/services.yaml Service descriptions for Home Assistant UI
custom_components/menstruation_cycle/statistics.py Analytics helpers and doctor-report generation
custom_components/menstruation_cycle/www/*.js Lovelace custom cards and shared assets
tests/*.js, tests/*.py Lightweight frontend and backend regression tests

Key concepts

DOMAIN

DOMAIN = "menstruation_cycle" is the integration namespace used for:

  • config-entry storage in hass.data
  • service names such as menstruation_cycle.refresh_cycle_model
  • HTTP paths like /menstruation_cycle/...
  • dispatcher signals and resource registration keys

STORAGE_KEY and persistence

STORAGE_KEY = "menstruation_cycle.history" is used by storage.py for persisted profile data. Stored blocks include:

  • history
  • period_duration_days
  • symptom_history
  • product_usage
  • pregnancy_data
  • menarche_data
  • pre_menarche_data
  • menopause_data
  • noncycle_data
  • cycle_length_override

Legacy storage key support

STORAGE_KEY_LEGACY = "menstruation_gauge.history" allows migration from the older domain naming. MenstruationStorage.async_load() checks the current store first, then the legacy store.

Services registration

__init__.py registers the domain services. Service definitions live in services.yaml, but the actual behavior and validation live in Python.

Lovelace resource serving

__init__.py builds versioned resource URLs from manifest.json and registers the JS bundles as Lovelace module resources. This keeps HACS installs easier and reduces manual resource setup.

Why this structure matters

  • manifest.json is required so Home Assistant can load the integration at all.
  • hacs.json makes the repository discoverable and correctly classified in HACS.
  • __init__.py, sensor.py, and config_flow.py separate setup, entity exposure, and UI configuration.
  • storage.py keeps history and related data persistent across restarts.
  • model.py isolates domain calculations from Home Assistant-specific code.
  • www/*.js contains the Lovelace resources served under /menstruation_cycle/....
  • services.yaml documents backend services in the Home Assistant service UI.

Contributing guidelines

  • Keep changes focused and small.
  • Preserve backward compatibility where practical, especially for legacy card names and stored data.
  • Update README or wiki pages when user-facing behavior changes.
  • Prefer extending existing patterns instead of introducing parallel implementations.

Code style expectations

  • Follow existing Python and JavaScript style in nearby files.
  • Reuse constants from const.py instead of repeating raw strings.
  • Keep UI labels and service names aligned with translations and services.yaml.
  • Avoid changing unrelated formatting while working on a narrow fix.

How to add a new card

  1. Add the new JS file under custom_components/menstruation_cycle/www/.
  2. Register the custom element and window.customCards metadata.
  3. Add the resource to the Lovelace resource tuple in __init__.py.
  4. Add or update tests in /tests for rendering or config behavior.
  5. Document the card in Cards-Documentation.md.

How to add a new service

  1. Define the service constant in const.py.
  2. Add the service schema and handler in __init__.py.
  3. Document it in services.yaml so it appears correctly in Home Assistant UI.
  4. Add backend tests when the logic is non-trivial.
  5. Add usage docs in Services-&-Automations.md.

Testing approach

Current tests are lightweight and close to the changed surface:

  • JavaScript card tests can be run directly with node tests/<file>.test.js
  • Backend behavior is covered by targeted Python tests in /tests
  • For docs-only changes, validate markdown structure, links, and affected examples manually

Common pitfalls

  • Forgetting to register a new frontend resource in __init__.py
  • Breaking compatibility with the older menstruation_gauge naming where migration support still matters
  • Updating frontend config options without updating editor UI or docs
  • Assuming cache refresh is enough when a backend restart is required
  • Adding new service behavior without reflecting it in services.yaml

Future roadmap ideas

  • richer symptom overlays in the heatmap
  • more clinical export/reporting options
  • broader household planning workflows
  • additional frontend editors and visualizations
  • expanded regression coverage for newer service areas