Repository navigation
v0.4.2
v0.4.2 - 2026-02-23
Added
integration_type: "hub"(manifest.json): Marks the integration as a hub so Home
Assistant displays it like the MQTT integration — with a CONFIGURE button and an
ADD DEVICE button on the integration card.single_config_entry: true(manifest.json): Only one Concierge Services instance
(one monitored email account) is allowed at a time.- Options Flow (
config_flow.py→OptionsFlowHandler): The CONFIGURE button
opens a pre-filled form to reconfigure the IMAP credentials and friendly name without
deleting and re-adding the integration. - Subentry Flow (
config_flow.py→ServiceSubentryFlowHandler): The ADD DEVICE
button scans the inbox, filters out services already added, and lets the user select one
new service account to add as a device. Each device also supports a reconfigure step
so the service name can be updated via the UI. - New constants (
const.py):CONF_SERVICE_ID,CONF_SERVICE_NAME,
CONF_SERVICE_TYPE,CONF_SAMPLE_FROM,CONF_SAMPLE_SUBJECT— used as keys in
subentry data instead of the old flatservices_metadatadict. - Subentry strings (
strings.json,translations/en.json,translations/es.json):
Newconfig_subentries.servicesection with step, error, and abort messages for the
add-device and reconfigure flows.
Changed
- Initial config flow (
config_flow.py): Simplified to two steps only — IMAP
credentials (user) and friendly name (finalize). Service detection during initial
setup has been removed; services are added individually after setup via ADD DEVICE. sensor.py:async_setup_entrynow iterates overconfig_entry.subentriesto
create service sensors, instead of reading from the oldservices/services_metadata
keys inconfig_entry.data. The coordinator reads effective credentials from
{**entry.data, **entry.options}so options-flow changes are respected without
needing to reconfigure from scratch.__init__.py: Removed explicit device-registry calls (devices are created via
DeviceInfoin the sensor entities). Added anadd_update_listenerso the entry
reloads automatically when options or subentries change.manifest.json: Version bumped to0.4.2.
Removed
CONF_SERVICESconstant fromconst.py(replaced by individual subentries).area_idsupport from the initial config flow (areas can still be assigned from the
device card after setup).detect_servicesandselect_servicessteps from the initial config flow.
Migration note
Existing config entries from v0.4.0/v0.4.1 will continue to load (the connection sensor
works without subentries). Previously configured service sensors will not appear
automatically — use the ADD DEVICE button to re-add them as subentries.
Added
-
Service-Type Constants (
const.py): AddedSERVICE_TYPE_WATER,SERVICE_TYPE_GAS,
SERVICE_TYPE_ELECTRICITY,SERVICE_TYPE_TELECOM, andSERVICE_TYPE_UNKNOWNconstants
to classify detected services. -
Modular Type-Specific Extractors (
attribute_extractor.py): Extraction tools are
now organised by service type so each utility category can use patterns tuned to its
own email format:Service type Extra attributes extracted wateraddress+customer_number(packed-values),consumption_m3,meter_reading,meter_numbergastotal_amount(plain-number override),metropuntos,consumption_m3(label-based)electricityfolio,boleta_date,address(fromubicado en),consumption_kwh,consumption_type,next_billing_period_start/end -
due_dateextraction (attribute_extractor.py): New generic extractor
(_extract_due_date) searches forFecha de vencimientolabel — confirmed in
both Metrogas and Enel emails. -
_extract_type_specific_attributesrouting helper (attribute_extractor.py):
Dispatches to the correct type-specific extractor based onservice_type. -
classify_service_typeutility (service_detector.py): Public function that
infers the service type from the emailFromaddress andSubjectline.
Changed
-
_strip_html(attribute_extractor.py): Now applieshtml.unescape()a second
time after the HTML parser so that double-encoded entities (ó→
ó→ó) found in Aguas Andinas emails are fully decoded. -
_CUSTOMER_LABELS(attribute_extractor.py): Madedeoptional so both
Número de Cliente:andNúmero Cliente:(Metrogas) are matched. -
_extract_from_subjectfolio patterns (attribute_extractor.py): Added
r"nro\.?\s+([0-9]{6,})"for the MetrogasBoleta Metrogas Nro. NNNNNNformat. -
SERVICE_PATTERNS(service_detector.py): 3-tuples with service type added. -
DetectedServicedataclass (service_detector.py): Addedservice_typefield. -
ConciergeServiceSensor.extra_state_attributes(sensor.py): Exposes
service_type; also filtersNoneattribute values so fields cleared by
type-specific extractors are omitted from the HA UI rather than shown asnull. -
Config flow (
config_flow.py): Storesservice_typeinservices_metadata.
Water extractor — Aguas Andinas (reference email: February 2026)
The Aguas Andinas HTML-only email uses a two-column table layout: labels
(Dirección:, Número de Cuenta:, Período de Facturación:) are in the left <td>;
all values are packed in the right <td> as a single paragraph:
ADDRESS ACCOUNT_NUM DATE al DATE.
| Root cause | Fix |
|---|---|
&oacute; double-encoded HTML entities |
_strip_html applies html.unescape() twice |
Labels and values in separate <td> — generic label extractor gives wrong results |
_WATER_AA_PACKED_RE detects the ALL-CAPS address + \d{5,}-\d account pattern; results override generic values via update() |
Fields now correctly extracted: billing_period_start/end ✓ total_amount ✓
address ✓ (was 'Número de Cuenta:') customer_number ✓ (was street number '385-515')
Gas extractor — Metrogas (reference email: January 2026)
- Folio from subject
Nro.pattern, plain-number total,metropuntosloyalty points. - Gas consumption (m³) is not in the email body — only in the PDF attachment.
Electricity extractor — Enel Distribución Chile (reference email: February 2026)
The Enel email has both text/plain and text/html parts; extractor uses plain text.
| What we learned | How it's handled |
|---|---|
Invoice number in body: N° Boleta 361692435 del 02-02-2026 |
_ELEC_ENEL_FOLIO_RE + _ELEC_ENEL_BOLETA_DATE_RE → folio + boleta_date |
Address follows ubicado en (not Dirección:) |
_ELEC_ENEL_ADDRESS_RE → address |
| No current billing period in email; first two dates are boleta date + due date (WRONG) | Electricity extractor sets billing_period_start/end = None; sensor filters None values |
Próximo periodo de facturación = NEXT billing period |
_ELEC_ENEL_NEXT_PERIOD_RE → next_billing_period_start/end |
Consumo real / Consumo estimado quality flag |
_ELEC_ENEL_CONSUMPTION_TYPE_RE → consumption_type |
505 kWh in email body |
bare-kWh fallback → consumption_kwh |