npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@twinforce/homebridge-miot

v0.2.3

Published

Native Apple Home integration for Xiaomi MIoT devices: Air Purifier 4 Compact over HomeKit and Robot Vacuum E10 over Matter.

Readme

@twinforce/homebridge-miot

A modular Homebridge plugin for Xiaomi MIoT devices with native controls in Apple Home.

| Device | MIoT model | Apple Home integration | | --- | --- | --- | | Xiaomi Smart Air Purifier 4 Compact | zhimi.airp.cpa4, xiaomi.airp.cpa4 | HomeKit Air Purifier, air quality, and filter maintenance | | Xiaomi Robot Vacuum E10 | xiaomi.vacuum.b112 | Matter Robotic Vacuum Cleaner |

The purifier uses standard HomeKit services. The E10 uses Homebridge's native Matter robot vacuum support, so Apple Home recognizes it as a robot vacuum. Neither device is represented by custom switches. Control is local through miIO/MIoT; Xiaomi Cloud is used only during setup.

Validation status: covered by automated tests, checked against published MIoT specifications, and tested against the public QR login initiation endpoint. E10 field feedback confirms Matter pairing, movement, pause, and cleaning-mode changes, but the revised command confirmation handling still needs physical validation. The complete hardware acceptance checklist and a complete Xiaomi account login have not been verified. This project is not an Apple-certified accessory or an official Xiaomi integration.

Air Purifier 4 Compact in Apple Home

| Feature | Native HomeKit mapping | | --- | --- | | Power | AirPurifier.Active | | Automatic / manual control | TargetAirPurifierState — Auto / Manual | | Current operation | CurrentAirPurifierState — inactive / idle / purifying | | Speed / Sleep | RotationSpeed: 0% Off, 1% Sleep, 2–100% for 15 Favorite levels | | Display brightness (optional) | Linked Lightbulb: 0% Off, 50% Dim, 100% On | | Physical button lock | LockPhysicalControls | | PM2.5 | AirQualitySensor.PM2_5Density, µg/m³ | | Air quality category | AirQuality | | Remaining filter life | FilterMaintenance.FilterLifeLevel, 0–100% | | Filter replacement required | FilterChangeIndication at 0% | | Fault | Standard StatusFault on the air quality service, with details in Homebridge logs | | Lost connection | A HomeKit communication error instead of returning stale state as current |

The speed slider selects Off at 0%, the actual Xiaomi Sleep mode at 1%, and Favorite (manual) at 2–100%. Sleep preserves the previously chosen Favorite level. All 15 Favorite levels remain available, so the reported manual percentage may be rounded. These percentages are control positions, not a measured percentage of power consumption. In Auto, the displayed speed is an estimate based on motor RPM.

HomeKit's native purifier mode selector supports only Auto and Manual. A third named Sleep option cannot be added to Apple Home through that service. Sleep is shown as Manual with the slider at 1%, including when selected in Xiaomi Home. Repeating Manual while already in Sleep preserves Sleep; move the slider above 1% to select Favorite. There is no separate Sleep switch.

Display control is disabled by default. In the plugin settings, open Add manually or edit configuration, find the purifier, and enable Expose purifier display in Apple Home; save and restart the bridge. Alternatively, add "exposeDisplay": true to that purifier's device entry. This adds a linked standard light named [Purifier name] Display, because HomeKit does not provide a display-brightness control within its AirPurifier service. Apple Home treats it as a light, including in lighting commands; the purifier itself remains an AirPurifier.

The display has three hardware settings: 0% Off, 50% Dim, 100% On. Intermediate requests map to Dim for 1–50% and On above 50%; the actual setting is read back and reported. Turning the display off does not turn the purifier off, and turning the display on does not start purification. During the current bridge session, turning it back on restores the last observed nonzero brightness. Without such a reading after a restart, On selects full brightness. Changes made on the purifier or in Xiaomi Home are picked up by polling. Disabling the option removes only the display control after restarting, preserving the purifier's pairing.

HomeKit does not provide a text error list or a StatusFault characteristic directly on the AirPurifier service. Fault code 2 (motor), code 3 (dust sensor), and unknown codes are logged only when they change; fault clearance and connectivity recovery are also logged. A dust sensor fault reports unknown air quality and makes the PM2.5 reading return an error.

Apple Home's presentation depends on its version. Standard filter and fault characteristics may appear in accessory details or in other HomeKit clients. A separate text message or Apple push notification is not guaranteed. Reset the filter in Xiaomi Home or on the device; the plugin does not expose a reset action that could accidentally erase filter wear.

The AirQuality category is the plugin's display policy, using PM2.5 thresholds of 12 / 35 / 55 / 150 µg/m³. It is neither Xiaomi's calibrated AQI nor a health assessment. Unsupported temperature, humidity, and PM10 readings are not created.

Robot Vacuum E10 in Apple Home

Apple Home's native robot vacuum support uses Matter. The E10 is published through Homebridge's Matter integration as a Robotic Vacuum Cleaner. It has its own pairing code and is not added through the purifier's HomeKit bridge pairing.

| Feature | Native Matter mapping | | --- | --- | | Start cleaning | RvcRunMode | | Pause / resume | RvcOperationalState commands | | Stop cleaning / return to dock | RvcRunMode Idle / RvcOperationalState.GoHome | | Vacuum, vacuum and mop, or mop | RvcCleanMode | | Suction and water levels | Native RvcCleanMode presets | | Actual activity | RvcOperationalState — stopped, running, paused, returning to dock, charging, or error | | Battery percentage and charging | PowerSource | | Find the robot | Audible Matter Identify | | Device fault | Native operational error, with the Xiaomi error code in Homebridge logs | | Lost connection | Native operational error and unknown battery; commands fail until communication recovers |

Pause is mapped to Xiaomi's stop-sweeping action to pause in place. Stop/Idle sends the return-to-dock action. Start and Resume use the robot's start-cleaning action. State is read back from the robot rather than assumed from a command being accepted. Change the cleaning mode while the robot is idle or charging and has no fault; actual setting changes during cleaning, pause, return to dock, or a firmware update are rejected. Repeating settings already reported by the robot succeeds without sending another command. Repeating the Cleaning run mode preserves a physical pause; use the native Resume command to resume.

Xiaomi may acknowledge a command before its properties reflect the change. The plugin accepts normal and pending acknowledgements, then polls the affected property with a three-second settling budget shared by the whole preset. It never repeats the action or write. Individual network requests and the final full state read can add time. A rejected or unconfirmed command still fails, but a successful fresh state read keeps the robot reachable and preserves its actual activity and battery. A failed state read still produces a communication error.

Only xiaomi.vacuum.b112 is supported. Similar product names such as E10C or E10 variants with another MIoT identifier must not be assumed compatible. The published E10 specification supplies numeric fault codes without a complete description for each value. The plugin preserves raw codes and treats unrecognized nonzero codes as native faults. One model-specific exception is 2105: an E10 field report showed it at 100% battery without a Xiaomi Home error, consistent with the fully charged indication documented by python-miio for Viomi. It does not create an operational error or block cleaning settings. This exception is based on observed behavior, not an official E10 error dictionary; other codes, including other values above 2000, are not silently ignored. Activity and battery still come from their own properties, not from this code. Apple Home decides how native modes, errors, and battery details are displayed. A communication failure is exposed as a native operational error; the Homebridge 2.4 API does not let this plugin guarantee an Apple Home “No Response” badge for the standalone robot.

The native cleaning-mode menu includes 17 choices:

| Choices | Settings changed | | --- | --- | | Vacuum / Vacuum and mop / Mop | Cleaning task only; existing suction and water settings are preserved | | Vacuum: suction 1–4 | Vacuuming with the selected suction level | | Vacuum and mop: suction 1–4 | Combined cleaning with the selected suction level; water is preserved | | Mop: water 1–3 | Mopping with the selected water level | | Vacuum and mop: water 1–3 | Combined cleaning with the selected water level; suction is preserved |

These are native cleaning modes, without additional switches or a simulated fan slider. Levels retain the numerical names from Xiaomi's specification. A selected preset remains reported only while the robot's actual settings match it; external changes can return the displayed selection to the corresponding base task. Apple Home may present a subset of native mode details, depending on its version.

Filter, brush, and mop life percentages remain in Xiaomi Home. The plugin logs a replacement reminder when a consumable reaches 0%, without resetting its wear. Room selection and maps are not exposed for this model.

If Apple Home stays on “Updating” after inactivity

The plugin reads the robot in the background at pollInterval even when no phone is using Apple Home. Matter manages controller subscriptions and their keepalives. An Apple Home “Updating” tile does not by itself mean the robot reports firmware-update status, and a successful Play Sound to Locate does not prove that passive subscription reports are reaching that controller. A similar Identify-dependent symptom was reported in Homebridge issue #3951; that report does not establish the cause in every installation.

To investigate a recurrence, enable Homebridge debug mode, restart the bridge, and capture the time when the tile becomes stuck before issuing another command. The plugin logs:

  • state read #…: a successful fresh Xiaomi reading, including activity, cleaning mode, battery, and raw fault; its update has been submitted to Homebridge.
  • Matter snapshot: the operational state, run mode, and battery currently readable from Homebridge's live Matter endpoint. The battery field uses Matter's half-percent units: 200 means 100%. This snapshot is not an acknowledgement from Apple Home.

Compare the tile on another Apple device at the same time, if available. Preserve nearby Matter subscription warnings such as reported invalid by peer and the plugin's refresh lines. Include Homebridge, iOS/macOS, and home hub versions, excluding tokens and pairing codes. If Xiaomi reads and Matter snapshots continue while a tile remains stuck, investigate the controller/subscription path instead of changing the robot's state. Do not reset the pairing as the first diagnostic step.

A field capture also revealed an independent error-recovery defect: the Matter endpoint retained the previous error description after its error code returned to zero. Recovery now explicitly clears the description. See the investigation and confirmed fix; whether it resolves the affected iPhone tile still needs field testing.

The idle refresh path is covered by six-hour simulated polling and recovery tests. Reproducing and resolving an Apple Home rendering/subscription failure still requires observations from an affected controller.

Enable Matter and pair the E10

  1. Install the plugin, import the E10 from Xiaomi Cloud or add it manually, and save the configuration.
  2. Enable Matter on the bridge running Xiaomi MIoT: use Settings → Matter Settings for the main bridge, or Plugins → Xiaomi MIoT → Child Bridge Settings → Enable Matter for a child bridge. Assign an available Matter port and restart that bridge. Keep HomeKit enabled for an existing purifier. See Homebridge's Matter setup guide.
  3. Find the E10's own Matter pairing QR code or PIN in Homebridge's Matter pairing information. In Apple Home, choose Add Accessory and scan that code. Robot vacuums receive a separate pairing code, so scanning the main bridge's QR code does not pair the robot.
  4. Assign the robot to a room in Apple Home and test its native cleaning controls.

Matter must be enabled on the actual main or child bridge that runs this plugin. The plugin does not create a substitute HomeKit switch when Matter is disabled. Homebridge currently describes its Matter implementation as experimental; keep that in mind when upgrading Homebridge. Back up the Homebridge Matter storage together with xiaomi-miot-matter-identities.json in the Homebridge storage directory. This identity file contains no credentials and retains inactive mappings so re-enabling a device can reuse its pairing identity.

Requirements

  • Homebridge 2.4.0 or later in the 2.x series; the current suite is tested with Homebridge 2.4.0 and HAP-NodeJS 2.2.2.
  • Node.js 22.12+, 24, or 26; local tests use Node 22.23.1. CI covers all three major versions.
  • A current Homebridge UI for guided setup, or manual editing of config.json.
  • For the E10, Matter enabled in Homebridge and an Apple Home version supporting robot vacuums; Apple introduced this in iOS 18.4. Keep your Apple devices and home hub up to date.
  • For Matter, working IPv6 and local multicast discovery between Homebridge and Apple Home. Docker on Linux should use host networking; exposing only the web UI port is insufficient.
  • Each device must already be paired with Xiaomi Home and reachable from Homebridge over UDP 54321.
  • A fixed IPv4 address or DHCP reservation. Container and VLAN networking must allow traffic to the device.
  • Internet access during login and import. After a device is saved, runtime control does not depend on Xiaomi Cloud.

Installation

The @twinforce/homebridge-miot package is public on npmjs.org. Installation requires no npm account or token. The source repository also remains public on GitHub.

Official Homebridge Docker image

For the homebridge/homebridge image, open Terminal in the Homebridge UI and run:

hb-service add @twinforce/homebridge-miot

Restart Homebridge from the UI, then open the Xiaomi MIoT plugin settings. The same installation can be performed from the Docker host; replace homebridge if your container has a different name:

docker exec -it homebridge hb-service add @twinforce/homebridge-miot
docker restart homebridge

Use the image's plugin manager so the plugin is installed in the directory Homebridge actually loads. Keep /homebridge on a persistent volume to retain plugins and configuration when recreating the container. The official Linux deployment uses host networking for discovery. See the Homebridge Docker configuration.

Other Homebridge installations

Install the package through Homebridge UI when available. For a setup that loads plugins from the global npm directory, use the same Node.js environment as Homebridge:

npm install -g @twinforce/homebridge-miot

Restart Homebridge and open Xiaomi MIoT settings. If your installation manages plugins in a dedicated directory, use its plugin manager instead of installing into an unrelated global directory.

Migrating from the earlier local package

If the unscoped homebridge-miot package is already installed, replace it with the @twinforce package. Stop Homebridge first. For a global npm installation:

npm uninstall -g homebridge-miot
npm install -g @twinforce/homebridge-miot

On a managed installation, remove the old plugin through its plugin manager and install the scoped package using the appropriate instructions above. Preserve configuration and accessory cache, then restart Homebridge.

Keep the platform: "XiaomiMiot" block and device identifiers. Homebridge 2 recognizes the unchanged platform name, and the plugin preserves existing accessory UUIDs. Do not load both packages together. Also update any plugins, disabledPlugins, or fully qualified platform names that refer to the old package name.

Installing a local build

npm ci
npm run check
npm pack

Install the generated archive using the method appropriate for your Homebridge setup. For a global npm installation:

npm install -g /absolute/path/to/twinforce-homebridge-miot-VERSION.tgz

Replace VERSION with the generated filename and copy the archive to the Homebridge host if needed. In Docker, use the container's Homebridge environment and persistent plugin directory. Release instructions are in docs/PUBLISHING.md.

Setup through Xiaomi Cloud

  1. In the plugin settings, choose the region used in Xiaomi Home; for Poland, this is usually Europe (de).
  2. Start Xiaomi login. Scan the QR code in Xiaomi Home and approve the login. A link to Xiaomi's login page is also available.
  3. Select a supported device from the discovered list and save the selection.
  4. Restart Homebridge. The purifier appears on the paired HomeKit bridge. For the E10, complete the separate Matter pairing described above.

The list includes unsupported models, but they cannot be imported. If Xiaomi does not return a local IP address or token, use manual configuration. Importing a device again updates its address and token while preserving its chosen name, stable identifier, and enabled state.

The plugin does not write account passwords, cookies, or sessions to disk. The setup session expires after 15 minutes and is cleared after import, logout, or closing the panel. Local device tokens are stored as plain text in config.json, like other Homebridge secrets; consider this when sharing configurations or backups. Tokens are neither logged nor stored in the accessory cache.

Xiaomi can change its undocumented login flow and token availability. If additional account verification is requested, complete it in Xiaomi Home and start a new login. Manual configuration remains independent of this flow.

Manual configuration

Use the manual configuration option in the plugin settings, or add a block to the platforms array in your existing Homebridge configuration:

{
  "platform": "XiaomiMiot",
  "name": "Xiaomi MIoT",
  "pollInterval": 15,
  "devices": [
    {
      "name": "Living room purifier",
      "model": "zhimi.airp.cpa4",
      "host": "192.168.1.50",
      "token": "0123456789abcdef0123456789abcdef",
      "id": "living-room-purifier",
      "enabled": true
    },
    {
      "name": "Robot vacuum",
      "model": "xiaomi.vacuum.b112",
      "host": "192.168.1.51",
      "token": "abcdef0123456789abcdef0123456789",
      "id": "robot-vacuum-e10",
      "enabled": true
    }
  ]
}

Both tokens above are examples. Supply each device's own 32-character LAN token, which is different from your Xiaomi account password. Use the device's actual model identifier. The E10 entry also requires Matter to be enabled and paired as described above.

  • pollInterval: 10–300 seconds, default 15. Each polling cycle starts after the previous cycle completes.
  • id: an optional stable identifier of your choice. Set it when first configuring a device manually and keep it when changing the IP address.
  • did: Xiaomi's device identifier, populated during import. Without id or did, accessory identity depends on the IP address.
  • enabled: false: stops publishing the device after a restart while retaining its configuration entry. A HomeKit purifier is removed from its bridge; a separately paired Matter robot may remain as an unavailable tile in Apple Home.

Importing an existing manually configured device at the same address preserves its accessory identity. A device that stops responding is not removed. Deleting its entry or disabling it stops publication after a restart and may affect automations. To permanently remove a separately paired E10, also remove its accessory in Apple Home. The plugin retains its identity mapping to support re-enabling the same device; preserve that file and Homebridge's Matter storage in backups.

Architecture and development

  • src/platform.ts: Homebridge lifecycle, accessory restoration, and reconciliation.
  • src/config.ts: configuration validation and stable device identity.
  • src/devices/registry.ts: registry of device families and their HomeKit or Matter adapters.
  • src/devices/profiles.ts: CPA4 protocol definitions, including property addresses, ranges, and fault codes.
  • src/devices/purifier.ts: purifier logic, command queue, polling, and write confirmation.
  • src/devices/vacuum-profile.ts and src/devices/vacuum.ts: E10 MIoT properties, actions, and state validation.
  • src/matter/vacuum-accessory.ts: the native Matter robot vacuum adapter.
  • src/matter/vacuum-modes.ts: native cleaning presets and their mapping to actual device settings.
  • src/matter/identity-store.ts: persistent Matter identity tracking and accessory reconciliation.
  • src/homekit/purifier-accessory.ts: mapping to standard HAP services.
  • src/miio/: independent UDP transport, encryption, response validation, and timeouts.
  • src/cloud/: temporary login and device discovery, independent of the Homebridge platform.
  • homebridge-ui/: setup UI and isolated import session.

To add a device family, implement a profile/controller and a native accessory adapter, register it in registry.ts, and update the model list in the configuration schema. Keep device-specific logic out of the platform and transport. Use native services appropriate to the device's actual functions.

CPA4 properties are read one at a time because of reported firmware problems with grouped reads. Reads and writes are queued; writes are confirmed by reading back state. Reads may be retried after a new handshake. A write whose reply is lost is not automatically repeated.

npm run typecheck
npm test
npm run build
npm pack --dry-run

Tests cover real HAP classes, a simulated UDP device, cryptographic vectors, failures and recovery, import, session expiry, and stable identity. Vacuum tests cover MIoT commands, authoritative state reads, native Matter controls, faults, battery, and accessory lifecycle. They do not replace testing with physical devices. See docs/HARDWARE-TEST.md for the acceptance checklist.

Releases

Every push or merged pull request to main runs the supported Node.js test matrix and automatically publishes the next stable patch to npm. Larger versions can be requested explicitly. Releases use npm Trusted Publishing without a stored npm token; see the one-time setup and release guide.

Technical references