feat: add Yeedi Floor 3 Station (kd0una) support with opt-in NGIOT port 443 MQTT - #3
Draft
Qmo37 wants to merge 1 commit into
Draft
Conversation
…MQTT - Add opt-in MQTT listener on port 443 (MQTT_LISTEN_PORT_NGIOT env var) for devices using NGIOT protocol (raw MQTT over TLS on port 443) - Auto-shift web TLS port to 8443 when NGIOT port is set to 443 - Add post-connect handshake (SetTime + setting2 config push) for newly connected bots, required by eco-ng devices after CONNACK - Register kd0una (Yeedi Floor 3 Station) in productIotMapUnofficial.json Existing users are unaffected — NGIOT binding is disabled by default. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Qmo37
added a commit
to Qmo37/client.py
that referenced
this pull request
Mar 18, 2026
Add hardware capability definition for the Yeedi Floor 3 Station (model ID kd0una, product K960_ACS_INT). Device uses eco-ng protocol (JSON over MQTT) and connects via MQTT over TLS on port 443. Capabilities include: battery, charge, clean (with area), fan speed (quiet/normal/max/max_plus), life span (brush/filter/side brush), map (full map support with trace and position), network, play sound, stats, water (4 levels + mop attached), station (auto empty, actions, state), settings (true detect, volume, carpet boost, child lock, mop wash freq), continuous cleaning, clean count, clean preference, error, custom command. Verified working via Bumper self-hosted server with a real device. Companion Bumper PR: DeebotUniverse/bumper#3 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request: Add Yeedi Floor 3 Station (kd0una) Support
Summary
Adds support for the Yeedi Floor 3 Station (model ID
kd0una, productK960_ACS_INT) to Bumper. This device uses the eco-ng protocol (JSON over MQTT) but connects via MQTT over TLS on port 443 instead of the standard 8883, requiring a new listener binding and a post-connect handshake sequence.Type of Change
Changes
1. MQTT Listener on Port 443 — NGIOT Binding (Opt-in)
Problem: The Yeedi Floor 3 Station initiates a raw MQTT v3.1.1 connection inside a TLS tunnel on port 443. Bumper's web server (HTTPS) also defaults to port 443, causing a conflict.
Solution: Opt-in NGIOT binding — the port 443 MQTT listener is only activated when
MQTT_LISTEN_PORT_NGIOTis explicitly set as an environment variable. Existing users are completely unaffected. When opt-in is enabled, the web TLS port automatically shifts to 8443 to avoid the conflict (still configurable viaWEB_SERVER_HTTPS_PORT).Files changed:
bumper/utils/settings.pyWEB_SERVER_TLS_LISTEN_PORT: int = int(os.environ.get("WEB_SERVER_HTTPS_PORT") or 443) WEB_SERVER_LISTEN_PORT: int = int(os.environ.get("WEB_SERVER_LISTEN_PORT") or 8007) MQTT_LISTEN_PORT: int = int(os.environ.get("MQTT_LISTEN_PORT") or 1883) MQTT_LISTEN_PORT_TLS: int = int(os.environ.get("MQTT_LISTEN_PORT_TLS") or 8883) + MQTT_LISTEN_PORT_NGIOT: int | None = ( + int(os.environ["MQTT_LISTEN_PORT_NGIOT"]) + if os.environ.get("MQTT_LISTEN_PORT_NGIOT") + else None + )Web TLS port auto-adjusts when NGIOT is enabled:
bumper/__init__.pyUsage — to enable NGIOT (e.g. systemd service or
.env):Web TLS automatically shifts to 8443. Override with
WEB_SERVER_HTTPS_PORTif needed.Default behavior (no env var set): Identical to current Bumper — no port 443 MQTT, web TLS stays on 443. Zero impact on existing users.
2. Device Class Registration
Problem:
kd0unais not in Bumper's product IoT map, so the robot doesn't appear inGetGlobalDeviceListAPI responses.Solution: Added entry to the unofficial product map.
bumper/web/plugins/api/pim/productIotMapUnofficial.jsonNo code changes needed —
appsvr.py:_include_product_iot_map_info()already scans both official and unofficial maps byclassid.3. Post-Connect Handshake (SetTime + Config Push)
Problem: After MQTT CONNECT + CONNACK, the real Ecovacs cloud sends a
SetTimecommand and asetting2configuration push. Without these, the robot may not respond to commands properly.Solution: Added
_send_bot_handshake()method toBumperMQTTServerPluginthat fires automatically when a bot connects.bumper/mqtt/server.pyNew imports at top of file:
Modified
on_broker_client_connected:async def on_broker_client_connected(self, client_id: str, client_session: Session) -> None: """On client connected.""" self._set_client_connected(client_id, True, client_session) + # Send post-connect handshake for bot devices (SetTime + config) + asyncio.create_task(self._send_bot_handshake(client_id))New method (appended before
on_broker_client_disconnected):Design notes:
asyncio.create_taskso it doesn't block the MQTT broker's connect callbackSetTimeis a standard eco-ng command that all devices handleDevice Details
MQTT Client ID format:
{device_id}@kd0una/{resource}DNS domains (TW region):
jmq-ngiot-tw.area.ww.ecouser.net(MQTT)iotin-ww.ecouser.net(IoT init)portal-ww.ecouser.net(REST portal)Testing
Confirmed Working
ret: ok)GetGlobalDeviceListREST API returns the devicegetBatterycommand relayed and response receivedgetPos) workingNot Yet Tested
setBlock/getBlock)getSleep)getDryingDuration— no deebot_client command class exists)Test Configuration
kd0una.pyhardware capability file (separate PR needed for DeebotUniverse/client.py)Checklist
Related Work
kd0una.pyneeds to be contributed to DeebotUniverse/client.py as a separate PR for native HA support without manual deploymentNotes for Reviewers
Port 443 is fully opt-in. The NGIOT binding only activates when
MQTT_LISTEN_PORT_NGIOTis set. Default behavior is unchanged — existing users are unaffected. When opted in, web TLS shifts automatically from 443 → 8443 to avoid the conflict, and is still overridable viaWEB_SERVER_HTTPS_PORT.The handshake benefits all eco-ng devices, not just kd0una. Many newer Ecovacs devices expect
SetTimeafter connect. This is a general improvement.The product map entry is data-only — no code change, just a JSON addition. Low risk.
No breaking API changes — all existing MQTT and REST behavior is preserved. The only difference is the web TLS default port number.