Zemismart

Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)

Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)
28 Marzo 2026 12 min di lettura 217 visite
Nota trasparenza: Questo articolo contiene link Amazon di affiliazione. Se acquisti tramite questi link, il blog puo ricevere una commissione senza costi aggiuntivi per te. Questo aiuta a sostenere le spese del progetto.

Bentornati su MissingTech.it! Oggi torniamo a parlare di uno degli argomenti che più ci appassionano quando si tratta di automazione domestica: il rilevamento della presenza. Se ci seguite da un po', sapete bene che passare da un classico sensore di movimento (PIR) a un sensore di presenza a microonde (mmWave) cambia letteralmente le regole del gioco in una smart home.

Il problema storico dei sensori mmWave, però, è sempre stato uno: l'alimentazione. La tecnologia radar è energivora e, fino a poco tempo fa, costringeva a tirare cavi USB antiestetici o a fare tracce nei muri. Oggi abbiamo tra le mani lo Zemismart ZPS-Z1, un sensore Zigbee che promette di tracciare la nostra presenza statica in modo totalmente wireless.

Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)

https://www.zemismart.com/products/zps-z1?DIST=RkRBGls%3D

Ma attenzione: se siete utenti di Home Assistant e usate l’integrazione ZHA, vi accorgerete subito che questo piccoletto fa i capricci. Niente paura: in questo articolo vedremo non solo come si comporta, ma anche come risolvere i problemi di compatibilità con un po' di sano soft hacking.

Design e Hardware: Il compromesso della batteria

Lo Zemismart ZPS-Z1 si presenta come un dispositivo estremamente compatto, dal design pulito e minimale. Ma il vero elemento di discussione si trova aprendo la scocca, e riguarda l'alimentazione. Il sensore è tenuto in vita da una singola batteria a bottone CR2450.

Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)

Conoscendo la "fame" di energia dei radar a microonde, la prima reazione è stata di forte scetticismo. Molti produttori affiancano un sensore PIR al radar per mandarlo in sleep e risparmiare batteria, ma nello ZPS-Z1 non c'è alcun PIR. La rilevazione è affidata al 100% al radar mmWave.

Come fa quindi a non prosciugare la batteria in due giorni? Indagando sui componenti interni, abbiamo scoperto che Zemismart ha utilizzato il chip Possumic RS2111 a 24GHz. Leggendo il datasheet di questo componente, emerge un dato impressionante: ha un consumo energetico ultra-basso, assorbendo appena 4μA durante gli eventi di rilevamento. Sulla carta, questo chip consuma quanto un vecchio e limitato sensore PIR, pur offrendo tutti i vantaggi della lettura spaziale a microonde. Una vera chicca ingegneristica che giustifica la scelta della singola batteria a bottone!

Il Problema su Home Assistant: Questione di "Fingerprint"

Essendo un dispositivo Zigbee 3.0, la prima cosa che abbiamo fatto è stata metterlo in modalità pairing per accoppiarlo al nostro Generic Zigbee Coordinator (EZSP) tramite ZHA. L'accoppiamento è stato immediato, ma ci siamo trovati davanti a un'amara sorpresa: dispositivo connesso, ma zero entità utili. Niente presenza, niente lux, niente configurazioni. Solo un generico sensore di stato LQI e l'indicazione dell'alimentazione a batteria.

Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)
Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)

Cosa è successo? Nel mondo Zigbee, quando un dispositivo si connette, invia al coordinatore la sua "fingerprint" (letteralmente la sua impronta digitale), per presentarsi. In questo caso, il sensore ha bussato alla porta di Home Assistant dicendo: "Ciao, sono il modello TS0601 prodotto da _TZE284_ft7qqpx3".

Home Assistant legge questa impronta per capire che lingua parla il sensore e caricare i driver corretti. Il problema è che i dispositivi dell'ecosistema Tuya utilizzano spesso cluster Zigbee non standard (nello specifico, mappano tutto sul cluster proprietario 0xEF00). Senza un "dizionario" specifico per quell'esatta fingerprint, ZHA non ha la più pallida idea di come interpretare i dati grezzi che il sensore sta inviando.

Soft Hacking: Risolviamo con i Quirk personalizzati

Per domare lo Zemismart ZPS-Z1 e costringere ZHA a tradurre correttamente le sue informazioni, dobbiamo ricorrere ai Quirk (dei driver personalizzati scritti in Python). Ecco come abbiamo fatto:

  • Abilitare i Quirk in HA: Accedendo ai file di configurazione di Home Assistant (se avete la vostra VM su Proxmox potete usare l'addon File editor o VS Code), create una cartella chiamata custom_zha_quirks dentro la directory principale /config.

  • Modificare il configuration.yaml: Aggiungete queste righe per dire a ZHA dove cercare i nuovi driver:

zha:
  custom_quirks_path: /config/custom_zha_quirks/
  • Inserire il file Python: All'interno della cartella appena creata, dovete caricare un file, creato da voi con estensione .py, che contiene il codice quirk con le istruzioni specifiche per la fingerprint _TZE284_ft7qqpx3. Copiate dunque in un file il seguente codice e salvatelo con estensione .py e caricatelo nella cartella creata in HA come vedete nella foto che segue.

"""ZHA custom quirk — Zemismart ZPS-Z1 24 GHz mmWave Presence Sensor."""

from typing import Final

import zigpy.types as t
from zigpy.quirks.v2 import QuirkBuilder
from zigpy.quirks.v2.homeassistant import EntityPlatform, EntityType
from zigpy.quirks.v2.homeassistant.binary_sensor import BinarySensorDeviceClass
from zigpy.zcl.foundation import ZCLAttributeDef
from zhaquirks.tuya import TUYA_CLUSTER_ID
from zhaquirks.tuya.mcu import DPToAttributeMapping, TuyaMCUCluster


# ── Enums ─────────────────────────────────────────────────────────────────────

class PresenceState(t.enum8):
    """ZPS-Z1 DP1 presence state."""
    absence      = 0x00
    presence     = 0x01
    sensor_close = 0x02


class AutoCalibrationState(t.enum8):
    """ZPS-Z1 DP103 auto-calibration state."""
    standby  = 0x00
    start    = 0x01
    learning = 0x02
    success  = 0x03
    fail     = 0x04
    cancel   = 0x05


class SensitivityPreset(t.enum8):
    """ZPS-Z1 DP112 sensitivity preset."""
    high   = 0x00
    medium = 0x01
    low    = 0x02
    custom = 0x03


# ── Custom Tuya MCU cluster ───────────────────────────────────────────────────

class ZpsZ1ManufCluster(TuyaMCUCluster):
    """ZPS-Z1 custom Tuya MCU cluster mapping all DPs to named attributes."""

    class AttributeDefs(TuyaMCUCluster.AttributeDefs):
        """ZPS-Z1 datapoint attribute definitions."""

        presence_state: Final = ZCLAttributeDef(
            id=0x0001,          # DP 1
            type=PresenceState,
            access="rp",
            is_manufacturer_specific=True,
        )
        detection_range: Final = ZCLAttributeDef(
            id=0x0002,          # DP 2
            type=t.uint32_t,
            access="rwp",
            is_manufacturer_specific=True,
        )
        illuminance: Final = ZCLAttributeDef(
            id=0x0065,          # DP 101 (0x65)
            type=t.uint32_t,
            access="rp",
            is_manufacturer_specific=True,
        )
        auto_calibration: Final = ZCLAttributeDef(
            id=0x0067,          # DP 103 (0x67)
            type=AutoCalibrationState,
            access="rwp",
            is_manufacturer_specific=True,
        )
        sensitivity_preset: Final = ZCLAttributeDef(
            id=0x0070,          # DP 112 (0x70)
            type=SensitivityPreset,
            access="rwp",
            is_manufacturer_specific=True,
        )
        presence_clear_cooldown: Final = ZCLAttributeDef(
            id=0x0077,          # DP 119 (0x77)
            type=t.uint32_t,
            access="rwp",
            is_manufacturer_specific=True,
        )
        led_indicator: Final = ZCLAttributeDef(
            id=0x007B,          # DP 123 (0x7B)
            type=t.Bool,
            access="rwp",
            is_manufacturer_specific=True,
        )

    dp_to_attribute: dict[int, DPToAttributeMapping] = {
        1: DPToAttributeMapping(
            ep_attribute=TuyaMCUCluster.ep_attribute,
            attribute_name="presence_state",
            converter=PresenceState,
        ),
        2: DPToAttributeMapping(
            ep_attribute=TuyaMCUCluster.ep_attribute,
            attribute_name="detection_range",
        ),
        101: DPToAttributeMapping(
            ep_attribute=TuyaMCUCluster.ep_attribute,
            attribute_name="illuminance",
        ),
        103: DPToAttributeMapping(
            ep_attribute=TuyaMCUCluster.ep_attribute,
            attribute_name="auto_calibration",
            converter=AutoCalibrationState,
        ),
        112: DPToAttributeMapping(
            ep_attribute=TuyaMCUCluster.ep_attribute,
            attribute_name="sensitivity_preset",
            converter=SensitivityPreset,
        ),
        119: DPToAttributeMapping(
            ep_attribute=TuyaMCUCluster.ep_attribute,
            attribute_name="presence_clear_cooldown",
        ),
        123: DPToAttributeMapping(
            ep_attribute=TuyaMCUCluster.ep_attribute,
            attribute_name="led_indicator",
        ),
    }

    data_point_handlers = {
        1:   "_dp_2_attr_update",
        2:   "_dp_2_attr_update",
        101: "_dp_2_attr_update",
        103: "_dp_2_attr_update",
        112: "_dp_2_attr_update",
        119: "_dp_2_attr_update",
        123: "_dp_2_attr_update",
    }


# ── Quirk registration ────────────────────────────────────────────────────────

(
    QuirkBuilder("_TZE284_ft7qqpx3", "TS0601")
    .adds(ZpsZ1ManufCluster)
    .skip_configuration()

    # DP1 — occupancy binary sensor (true/false for automations)
    .binary_sensor(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.presence_state.name,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        device_class=BinarySensorDeviceClass.OCCUPANCY,
        entity_type=EntityType.STANDARD,
        fallback_name="Occupancy",
        translation_key="occupancy",
        attribute_initialized_from_cache=False,
    )

    # DP1 — presence_state enum sensor (all 3 states visible)
    .enum(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.presence_state.name,
        enum_class=PresenceState,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        entity_platform=EntityPlatform.SENSOR,
        entity_type=EntityType.STANDARD,
        fallback_name="Presence state",
        translation_key="presence_state",
    )

    # DP101 — illuminance sensor (lux)
    .sensor(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.illuminance.name,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        fallback_name="Illuminance",
        translation_key="illuminance",
    )

    # DP2 — detection_range number (0–500 cm)
    .number(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.detection_range.name,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        min_value=0,
        max_value=500,
        step=50,
        fallback_name="Detection range",
        translation_key="detection_range",
        entity_type=EntityType.CONFIG,
    )

    # DP119 — presence_clear_cooldown number (2–60 s)
    .number(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.presence_clear_cooldown.name,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        min_value=2,
        max_value=60,
        step=1,
        fallback_name="Presence clear cooldown",
        translation_key="presence_clear_cooldown",
        entity_type=EntityType.CONFIG,
    )

    # DP103 — auto_calibration select
    .enum(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.auto_calibration.name,
        enum_class=AutoCalibrationState,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        entity_platform=EntityPlatform.SELECT,
        entity_type=EntityType.CONFIG,
        fallback_name="Auto calibration",
        translation_key="auto_calibration",
    )

    # DP112 — sensitivity_preset select
    .enum(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.sensitivity_preset.name,
        enum_class=SensitivityPreset,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        entity_platform=EntityPlatform.SELECT,
        entity_type=EntityType.CONFIG,
        fallback_name="Sensitivity preset",
        translation_key="sensitivity_preset",
    )

    # DP123 — led_indicator switch
    .switch(
        attribute_name=ZpsZ1ManufCluster.AttributeDefs.led_indicator.name,
        cluster_id=TUYA_CLUSTER_ID,
        endpoint_id=1,
        fallback_name="LED indicator",
        translation_key="led_indicator",
        entity_type=EntityType.CONFIG,
    )

    .add_to_registry()
)
Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)
  • Riavvio e Ri-accoppiamento: Dopo aver riavviato Home Assistant, abbiamo eliminato il sensore da ZHA e rifatto la procedura di pairing.

Risultato? Magia. Sono apparse istantaneamente tutte le entità: lo stato di Presenza, il valore della luminosità e tutti i parametri di configurazione vitali, come la sensibilità del radar e il tempo di mantenimento dello stato (fading time).

Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)

Ecosistema Nativo: Perché non usiamo Tuya

Una piccola ma doverosa precisazione: se non volete impazzire con i quirk e i file di configurazione, lo Zemismart ZPS-Z1 funziona in modo assolutamente perfetto (e plug and play) all'interno del suo ambiente nativo.

Tuttavia, per farlo, avrete necessariamente bisogno di un Hub Zigbee compatibile con l'app Tuya Smart.

Non ci siamo dedicati all'installazione su Tuya semplicemente perché sappiamo che il pubblico di MissingTech ama Home Assistant, il controllo locale, la privacy e la reattività istantanea che solo un sistema slegato dal cloud può offrire.

La Comparativa: Zemismart vs SwitchBot vs Aqara FP300

Avendo già recensito in passato altri due pesi massimi del settore, è d'obbligo fare un confronto diretto per capire come si posiziona questo ZPS-Z1.

Recensione SwitchBot Presence Sensor: La presenza smart diventa (finalmente) senza fili

Aqara FP300 Presence Multi-Sensor - mmWave, Pir, Light, Temeprature, Humidity. Zigbee Thread Matter

Recensione Zemismart ZPS-Z1: Il sensore mmWave a batteria e come domarlo su ZHA (Soft Hacking)

La differenza tra 24GHz e 60GHz: Guardando la tabella salta all'occhio un dettaglio tecnico fondamentale. Mentre lo Zemismart utilizza un radar a 24GHz, sia lo SwitchBot che l'Aqara sfruttano il fratello maggiore: il chip Possumic RS6130 a 60GHz.

  • Cosa significa all'atto pratico? I radar a 60GHz offrono una risoluzione maggiore e sono incredibilmente sensibili ai micro-movimenti (come il respiro), ma richiedono molta più energia (ecco perché SwitchBot usa le AAA e Aqara ben due CR2450) e costano di più.

  • Zemismart ha scelto il compromesso intelligente: il 24GHz è leggermente meno "chirurgico" sui movimenti impercettibili rispetto al 60GHz, ma garantisce consumi irrisori (i famosi 4μA) permettendo un design super sottile e un prezzo di vendita decisamente più aggressivo, pur stracciando le prestazioni di qualsiasi sensore PIR classico.

Quale scegliere? 

Se cercate un dispositivo Bluetooth da integrare facilmente tramite gli Shelly usati come proxy, lo SwitchBot rimane una scelta solidissima e con ottime batterie AAA.

  • Se volete il massimo della precisione e una suite completa di sensori ambientali, l'Aqara FP300 è il re indiscusso (pur costando di più).

  • Lo Zemismart ZPS-Z1 si infila esattamente nel mezzo: è la scelta perfetta per chi ha una rete mesh Zigbee robusta, vuole spendere il giusto e cerca un dispositivo compatto che faccia (bene) il suo dovere di base.

Pro e Contro

👍 I Pro:

  • Totalmente Wireless: Niente cavi, si installa in 30 secondi e si nasconde facilmente.

  • Ingegneria Top: L'uso del chip Possumic a 24GHz unisce la precisione del mmWave ai consumi ridottissimi di un PIR.

  • Batteria economica: La singola CR2450 costa pochissimo ed è reperibile ovunque.

  • Prezzo: Decisamente competitivo nel panorama dei sensori di presenza.

👎 I Contro:

  • Meno "chirurgico" dei top di gamma: Il radar a 24GHz è ottimo, ma sui micro-movimenti non eguaglia la precisione assoluta dei chip a 60GHz montati su Aqara o SwitchBot.

  • Niente "Plug and Play" su ZHA: Richiede un po' di "smanettamento" iniziale con i Quirk per essere integrato a dovere.

Conclusioni

Lo Zemismart ZPS-Z1 è un sensore che ci è piaciuto. Risolve il problema del cablaggio e offre la precisione delle microonde a un prezzo accessibile. L'intoppo iniziale su ZHA fa parte del gioco per noi appassionati e, una volta configurato, il dispositivo si è dimostrato stabile e reattivo.

Non dimenticate di iscrivervi al nostro Canale Telegram per non perdervi le prossime recensioni, guide e le migliori offerte tech!

Video YouTube