1.5.2
E-bloc România v1.5.2
Data: 2026-04-06
Versiune: v1.5.2
Tip: Bug fix + Refactorizare arhitectură
Problema
Toate entitățile (senzori, selectori, butoane) din toate asociațiile erau grupate sub un singur dispozitiv E-bloc România (10001) în Home Assistant. Un utilizator cu 3 asociații (50100, 50200, 50300) vedea totul la grămadă, fără separare logică.
În plus, entitățile din asociații diferite aveau coliziuni de entity_id — de exemplu sensor.ebloc_10001_factura_restanta exista o singură dată, deși ar fi trebuit să existe câte una per asociație.
Cauza rădăcină
DeviceInfo.identifiers folosea doar id_user ca identificator unic:
identifiers={(DOMAIN, str(id_user))}Toate entitățile, indiferent de asociație, raportau același device. Home Assistant grupează entitățile după identifiers — dacă toate au aceeași valoare, toate ajung sub același dispozitiv.
Același lucru și la entity_id și unique_id — lipsea id_asoc, ceea ce cauza coliziuni între asociații.
Soluția aplicată
1. Dispozitive separate per asociație
Funcția _global_device(id_user) a fost eliminată complet. Înlocuită cu _association_device(id_user, id_asoc):
def _association_device(id_user: int, id_asoc) -> DeviceInfo:
return DeviceInfo(
identifiers={(DOMAIN, f"{id_user}_{id_asoc}")},
name=f"E-bloc România ({id_asoc})",
manufacturer="Ciprian Nicolae (cnecrea)",
model="E-bloc România",
entry_type=DeviceEntryType.SERVICE,
)Rezultat: fiecare asociație are propriul dispozitiv în HA.
2. Entități globale (Cont utilizator, Carduri salvate)
Aceste entități nu aparțin unei asociații specifice, dar nu mai avem dispozitiv global. Soluția: sunt atribuite primei asociații din coordinator data, prin funcția _first_association_id().
3. id_asoc inclus în toate identificatoarele per-asociație
Fișiere modificate: sensor.py, button.py, number.py
sensor.py — Senzori per asociație
| Entitate | unique_id (înainte) | unique_id (după) |
|---|---|---|
| AsociatieSensor | {DOMAIN}_{id_user}_asociatie |
{DOMAIN}_{id_user}_{id_asoc}_asociatie |
| IndexContorSensor | {DOMAIN}_{id_user}_{id_contor} |
{DOMAIN}_{id_user}_{id_asoc}_{id_contor} |
| FacturaRestantaSensor | {DOMAIN}_{id_user}_{id_ap}_factura_restanta |
{DOMAIN}_{id_user}_{id_asoc}_{id_ap}_factura_restanta |
| ArhivaPlatiSensor | {DOMAIN}_{id_user}_{id_ap}_plati |
{DOMAIN}_{id_user}_{id_asoc}_{id_ap}_plati |
| NrPersoaneSensor | {DOMAIN}_{id_user}_{id_ap}_nr_pers |
{DOMAIN}_{id_user}_{id_asoc}_{id_ap}_nr_pers |
| TicheteSensor | {DOMAIN}_{id_user}_{id_ap}_tichete |
{DOMAIN}_{id_user}_{id_asoc}_{id_ap}_tichete |
| CitirePermisaSensor | {DOMAIN}_{id_user}_{id_ap}_citire_permisa |
{DOMAIN}_{id_user}_{id_asoc}_{id_ap}_citire_permisa |
Toate _custom_entity_id au fost actualizate cu același pattern (ex: sensor.ebloc_10001_50100_factura_restanta).
button.py — Butoane per asociație
| Entitate | unique_id (după) | entity_id (după) |
|---|---|---|
| TrimiteIndexButton | {DOMAIN}_{id_user}_{id_asoc}_{id_contor}_trimite_index |
button.{DOMAIN}_{id_user}_{id_asoc}_trimite_index_{titlu_slug} |
| TrimiteNrPersButton | {DOMAIN}_{id_user}_{id_asoc}_{id_ap}_trimite_nr_pers |
button.{DOMAIN}_{id_user}_{id_asoc}_trimite_nr_persoane |
number.py — Selectori per asociație
| Entitate | unique_id (după) | entity_id (după) |
|---|---|---|
| NrPersoaneNumber | {DOMAIN}_{id_user}_{id_asoc}_{id_ap}_nr_pers |
number.{DOMAIN}_{id_user}_{id_asoc}_nr_persoane_selector |
| IndexContorNumber | {DOMAIN}_{id_user}_{id_asoc}_{id_contor}_index |
number.{DOMAIN}_{id_user}_{id_asoc}_index_{titlu_slug}_selector |
4. Consistență cross-file (button ↔ number)
Verificat și confirmat:
TrimiteIndexButton._number_uid=IndexContorNumber._attr_unique_id={DOMAIN}_{id_user}_{id_asoc}_{id_contor}_index✓TrimiteNrPersButton._number_uid=NrPersoaneNumber._attr_unique_id={DOMAIN}_{id_user}_{id_asoc}_{id_ap}_nr_pers✓
5. Bug critic reparat: cod mort în number.py
Inițializarea self._value (fallback cu ultimul index/nr. persoane din API) era plasată după return în proprietatea device_info — nu se executa niciodată. La runtime ar fi cauzat AttributeError pe native_value.
Reparat în ambele clase: NrPersoaneNumber și IndexContorNumber.
6. Coordinator: gestionare nologin pe ContoareGetIndexLuni
AppContoareGetIndexLuni.php returnează nologin selectiv pe unele asociații. Codul anterior nu detecta acest caz — nu era excepție, ci un răspuns valid cu aLuni: [].
Reparat:
- Detecție explicită
result == "nologin"cu marcare pentru retry - Re-autentificare automată (
async_ensure_authenticated()) + retry doar pentru asociațiile afectate - Fallback robust:
luna or datetime.now().strftime("%Y-%m")în loc de string gol - Logging la nivel INFO pentru fiecare asociație (sursă luna: GetIndexLuni sau fallback)
Clasele de bază actualizate
EblocEntity.device_info, EblocNumber.device_info și EblocButton.device_info — toate folosesc acum {id_user}_{id_asoc} ca pattern de identificare. Nu mai există nicio referință la _global_device sau la str(id_user) singur ca identifier.
Impact la upgrade
ATENȚIE: Această modificare schimbă unique_id și entity_id pentru toate entitățile per-asociație. La upgrade:
- Entitățile vechi vor fi șterse automat din registry (unique_id diferit)
- Entitățile noi vor fi create cu noile ID-uri
- Automatizările, dashboard-urile și scripturile care referențiază entity_id-urile vechi trebuie actualizate manual
- Dispozitivul global anterior (ex:
E-bloc România (10001)) va rămâne orfan și poate fi șters manual din Setări → Dispozitive
📈 Integrarea în cifre
| ⭐ Stars | 📥 Instalări | 🔄 Clone (14z) |
|---|---|---|
| 17 | 643 | 369 |
Dacă integrarea E-bloc România îți este utilă, lasă un ⭐ pe repository — îi ajută și pe alți utilizatori să o descopere.
💛 Dezvoltarea consumă timp și resurse. Dacă vrei să susții proiectul:
☕ Buy Me a Coffee · 💰 GitHub Sponsors