Pin ha-n95-local-control tag v0.1.2 (7bed99cc4c3222bad648efcddcdfed95652277f7). Health bind failure no longer takes down 8007/8005/5223 when OTBR owns 8080.
257 lines
12 KiB
Markdown
257 lines
12 KiB
Markdown
# Deebot N95 Local Control — documentation
|
||
|
||
Full installation, network, configuration, verification, and troubleshooting
|
||
information for the **Deebot N95 Local Control** Home Assistant add-on.
|
||
|
||
## How it works
|
||
|
||
The add-on replaces the legacy Ecovacs bootstrap and XMPP destinations used by
|
||
an already-provisioned Deebot N95, then exposes the robot through Home
|
||
Assistant MQTT discovery.
|
||
|
||
```text
|
||
N95 ── DNS ──> your LAN resolver
|
||
N95 ── HTTP 8007 / 8005, XMPP 5223 ──> this add-on ──> MQTT broker ──> Home Assistant
|
||
```
|
||
|
||
The add-on does not provision a robot and does not run a DNS server. It supports
|
||
multiple robots; each robot receives its own MQTT client and topic tree after
|
||
it reaches XMPP READY state and reveals its serial number.
|
||
|
||
## Before you start
|
||
|
||
You need:
|
||
|
||
* An already-provisioned Deebot N95 using the captured `wukong` / class `155`
|
||
protocol. Other Ecovacs models are not established as compatible.
|
||
* A stable LAN IPv4 address for the Home Assistant host, reserved in DHCP.
|
||
* Control of the DNS resolver supplied to the robot by DHCP.
|
||
* TCP `8007`, `8005`, and `5223` available on the Home Assistant host and
|
||
reachable from the robot. TCP `8080` is used for health checks.
|
||
* A broker reachable from the Home Assistant host and Home Assistant MQTT
|
||
configured with discovery enabled.
|
||
* A correct host clock and IANA timezone.
|
||
|
||
The robot caches its XMPP address after boot. If the address or listener ports
|
||
change, update DNS/configuration and reboot the robot; an ordinary reconnect
|
||
continues to use the cached destination.
|
||
|
||
## Step 1 — reserve the host address and configure DNS
|
||
|
||
Reserve the Home Assistant host's LAN IPv4 address. Configure the resolver sent
|
||
to the robot by DHCP with this A record:
|
||
|
||
```text
|
||
lbo.ecouser.net A <HOME_ASSISTANT_LAN_IPV4>
|
||
```
|
||
|
||
Set the add-on's `advertise_ip` to the same literal IPv4 address. Do not use
|
||
`0.0.0.0`, a container address, or a hostname. The `155.ecorobot.net` XMPP JID
|
||
domain does not need a DNS override for the captured firmware.
|
||
|
||
## Step 2 — install and configure
|
||
|
||
1. Add this repository in Home Assistant
|
||
(**Settings → Add-ons → Add-on Store → ⋮ → Repositories**):
|
||
`https://git.i3omb.com/gronod/ha-gronod-addons`
|
||
2. Install **Deebot N95 Local Control**.
|
||
3. Enter the reserved host IPv4 under **Advertised IP address**.
|
||
4. Select the correct IANA timezone, for example `Europe/London`.
|
||
5. Leave advanced listener values unset unless their default ports conflict.
|
||
|
||
When a Supervisor MQTT service is available, the add-on automatically reads
|
||
its host, port, TLS flag, username, and password. Every manually supplied MQTT
|
||
option overrides only that individual discovered field. This permits, for
|
||
example, using discovered credentials with a manually supplied private CA.
|
||
|
||
For an external broker with no Supervisor service, set at least `mqtt_host` and
|
||
any required credentials/TLS options.
|
||
|
||
## Step 3 — start and redirect the robot
|
||
|
||
Start the add-on and inspect its log. Verify the DNS and HTTP endpoints using
|
||
the checks below, then reboot the robot. The robot should bootstrap through the
|
||
lookup endpoint, open XMPP to the add-on, and appear as an MQTT vacuum in Home
|
||
Assistant.
|
||
|
||
No MQTT connection is expected when the add-on first starts. The bridge creates
|
||
a broker client only after a robot reaches XMPP READY and identifies itself.
|
||
|
||
## Configuration
|
||
|
||
Normal setup shows `advertise_ip`, `timezone`, and `log_level`. Select **Show
|
||
unused optional configuration options** to reveal MQTT overrides and advanced
|
||
network/protocol controls.
|
||
|
||
| Option | Default | Environment | Description |
|
||
|---|---|---|---|
|
||
| `advertise_ip` | required | `ADVERTISE_IP` | Stable, nonzero host IPv4 returned in lookup responses |
|
||
| `timezone` | `Etc/UTC` | `TZ` | IANA timezone controlling the local offset sent to the robot |
|
||
| `log_level` | `info` | `LOG_LEVEL` | `debug`, `info`, `warn`, or `error` |
|
||
| `bind_address` | `0.0.0.0` | `BIND_ADDRESS` | Advanced listener bind IP; normally leave unset |
|
||
| `port_lookup` | `8007` | `PORT_LOOKUP` | Advanced HTTP `POST /lookup.do` listener |
|
||
| `port_firmware` | `8005` | `PORT_FIRMWARE` | Advanced firmware-check listener; expected to return 404 |
|
||
| `port_xmpp` | `5223` | `PORT_XMPP` | Advanced plaintext robot XMPP listener |
|
||
| `health_port` | `8080` | `HEALTH_PORT` | Advanced HTTP `GET /healthz` listener. Bind failure is non-fatal from v0.1.2; robot ports stay up. Pick another port if OTBR already owns 8080. |
|
||
| `mqtt_host` | Supervisor/required | `MQTT_HOST` | Broker host without scheme or port; overrides discovery |
|
||
| `mqtt_port` | `1883`/`8883` | `MQTT_PORT` | Broker port; upstream chooses 8883 when TLS is enabled |
|
||
| `mqtt_tls` | `false` | `MQTT_TLS` | Start the MQTT connection with TLS and hostname verification |
|
||
| `mqtt_ca_file` | unset | `MQTT_CA_FILE` | Readable PEM CA bundle, normally `/ssl/<file>.pem` |
|
||
| `mqtt_username` | Supervisor/unset | `MQTT_USERNAME` | Broker username override |
|
||
| `mqtt_password` | Supervisor/unset | `MQTT_PASSWORD` | Broker password override; nonempty requires username |
|
||
| `mqtt_client_id` | `n95bridge-<hostname>` | `MQTT_CLIENT_ID` | Client ID prefix; `[A-Za-z0-9_-]{1,64}` |
|
||
| `mqtt_base` | `ecovacs` | `MQTT_BASE` | One MQTT topic level before `/<serial>` |
|
||
| `ha_discovery_prefix` | `homeassistant` | `HA_DISCOVERY_PREFIX` | Must match Home Assistant MQTT discovery prefix |
|
||
| `controller_jid` | `n95bridge@ecouser.net/homeassistant` | `CONTROLLER_JID` | Advanced virtual controller JID in `local@domain/resource` form |
|
||
| `raw_commands` | `false` | `RAW_COMMANDS` | Risky protocol-level raw command input; keep disabled normally |
|
||
|
||
Optional values are exported only when configured, preserving upstream
|
||
defaults. Boolean values are passed as lowercase `true` or `false`. All four
|
||
listener ports must be distinct and in the range 1–65535.
|
||
|
||
## Host networking and ports
|
||
|
||
The add-on uses host networking because the robot must connect to the exact
|
||
address and ports returned by `/lookup.do`. The same ports are declared in
|
||
`config.yaml` so Supervisor opens them on the Home Assistant OS host
|
||
firewall. Without that map, the process can listen on the host while LAN
|
||
clients (including the robot) time out.
|
||
|
||
| Port | Purpose | Robot access |
|
||
|---|---|---|
|
||
| `8007/tcp` | Bootstrap lookup (`EcoMsgNew`, `EcoUpdate`) | required |
|
||
| `8005/tcp` | Firmware check (expected 404 response) | required |
|
||
| `5223/tcp` | Plaintext XMPP | required |
|
||
| `8080/tcp` | Health endpoint | not required |
|
||
|
||
Changing a robot-facing port changes both the listener and the value advertised
|
||
to the robot. Also change the matching `ports:` entry so Supervisor still
|
||
opens the host firewall for that port. Check that another host service does
|
||
not already occupy the port. Host networking means Docker does not remap
|
||
these ports; the `ports` map is for Supervisor visibility and firewall
|
||
allowance only.
|
||
|
||
## MQTT and Home Assistant discovery
|
||
|
||
Supervisor MQTT values are loaded first; explicitly configured options then
|
||
replace individual fields. The final broker host must come from one of those
|
||
sources or the add-on exits with an actionable error.
|
||
|
||
For TLS with a private CA, place a readable PEM bundle in Home Assistant's
|
||
`ssl` directory and set `mqtt_ca_file` to its in-container path, such as
|
||
`/ssl/broker-ca.pem`. TLS hostname verification remains enabled, so
|
||
`mqtt_host` must match the broker certificate.
|
||
|
||
The bridge publishes discovery below
|
||
`<ha_discovery_prefix>/vacuum/ecovacs_<serial>/config` and robot data below
|
||
`<mqtt_base>/<serial>/...`. Broker ACLs must allow each generated client to
|
||
publish/subscribe under those trees. The default client prefix is based on the
|
||
add-on hostname and has the robot serial appended.
|
||
|
||
## Robot features and entities
|
||
|
||
The tagged upstream release publishes a native MQTT vacuum with availability,
|
||
state, battery, fan speed, error information, and start, stop, dock, spot, and
|
||
locate commands. It also supports extension movement commands, cleaning modes,
|
||
schedule CRUD, consumable lifespan state, and diagnostic topics. Pause, resume,
|
||
mapping, and segment cleaning are not advertised. Multiple connected robots remain isolated by
|
||
serial number.
|
||
|
||
`raw_commands` permits protocol-level `<ctl>` input intended for controlled
|
||
experimentation. It bypasses normal high-level command constraints and should
|
||
remain disabled for ordinary use.
|
||
|
||
## Check the installation
|
||
|
||
Replace the example addresses with your resolver and Home Assistant host:
|
||
|
||
```sh
|
||
nslookup lbo.ecouser.net 192.0.2.53
|
||
curl -sS -X POST -H 'Content-Type: application/json' \
|
||
--data '{"todo":"FindBest","service":"EcoMsgNew"}' \
|
||
http://192.0.2.10:8007/lookup.do
|
||
curl -sS -X POST -H 'Content-Type: application/json' \
|
||
--data '{"todo":"FindBest","service":"EcoUpdate"}' \
|
||
http://192.0.2.10:8007/lookup.do
|
||
curl -i http://192.0.2.10:8005/products/wukong/class/155/firmware/latest.json
|
||
curl -sS http://192.0.2.10:8080/healthz
|
||
```
|
||
|
||
The lookup responses must contain the configured advertised IPv4 and numeric
|
||
ports. The firmware request should return HTTP 404. The health endpoint should
|
||
report healthy listeners. After these pass, reboot the robot and check:
|
||
|
||
1. the add-on log for XMPP READY and the robot serial;
|
||
2. broker activity below `ecovacs/<serial>` and the discovery prefix;
|
||
3. a newly discovered MQTT vacuum entity in Home Assistant;
|
||
4. state refresh and a harmless command such as locating the robot.
|
||
|
||
## Security notes
|
||
|
||
* Robot XMPP, including SASL PLAIN credentials, is plaintext. Keep ports 8005,
|
||
8007, and 5223 restricted to the trusted robot LAN.
|
||
* MQTT authentication and TLS protect only the broker connection; they do not
|
||
encrypt robot traffic.
|
||
* Protect broker passwords and private CA files. The wrapper and upstream
|
||
configuration log do not print the MQTT password.
|
||
* Do not expose the robot-facing listeners to the internet.
|
||
|
||
## Troubleshooting
|
||
|
||
**The add-on exits with “No MQTT broker is available”**
|
||
No Supervisor MQTT service was found and `mqtt_host` is unset. Install/configure
|
||
a broker service or enter the external broker host.
|
||
|
||
**The robot still contacts the cloud**
|
||
Query the exact resolver supplied by DHCP and confirm `lbo.ecouser.net` returns
|
||
`advertise_ip`. Remove cached/secondary public DNS paths, then reboot the robot.
|
||
|
||
**LAN clients time out on 8007 even though the add-on log shows listeners**
|
||
On Home Assistant OS, Supervisor only opens inbound host ports listed under
|
||
`ports:` in `config.yaml`. Version 0.1.1 declares 8007, 8005, 5223, and 8080.
|
||
Rebuild/update the add-on so that version is installed, then confirm the
|
||
Network tab lists those ports. Loopback on the HAOS box can succeed while
|
||
the robot still times out if the firewall hole is missing.
|
||
|
||
**8007/8005/5223 never appear on the host while 8080 is owned by OTBR**
|
||
Before v0.1.2 a busy health port stopped every listener. From v0.1.2 the
|
||
process logs `health listener failed; robot listeners continue` and keeps
|
||
8007/8005/5223. Set optional `health_port` to a free port if you want
|
||
`/healthz`. Rebuild so the add-on is 0.1.2.
|
||
|
||
**The add-on reports an address-already-in-use error**
|
||
Another host service owns lookup, firmware, or XMPP. Stop that service or
|
||
set a distinct optional port. Reboot the robot after changing advertised ports.
|
||
|
||
**The robot does not reconnect after an address or port change**
|
||
The N95 caches XMPP details for its powered-on lifetime. Power-cycle/reboot it
|
||
to force a new bootstrap lookup.
|
||
|
||
**There is no MQTT connection immediately after startup**
|
||
This is expected until a robot reaches XMPP READY and provides its serial.
|
||
Investigate DNS, listener reachability, and XMPP logs first.
|
||
|
||
**The robot connects but no entity appears**
|
||
Confirm Home Assistant MQTT discovery is enabled and
|
||
`ha_discovery_prefix` matches its configured prefix. Check broker ACLs for both
|
||
the discovery and robot topic trees.
|
||
|
||
**MQTT authentication or TLS fails**
|
||
Check the effective host, port, username, and TLS override combination. For a
|
||
private CA, verify the `/ssl/...` path exists and is readable, and that the
|
||
broker certificate matches `mqtt_host`.
|
||
|
||
**Schedules run at the wrong time**
|
||
Set `timezone` to the correct IANA name and restart the add-on, then reconnect
|
||
the robot so it receives the updated time and UTC offset.
|
||
|
||
## Upstream and standalone usage
|
||
|
||
The add-on builds the immutable
|
||
[ha-n95-local-control v0.1.2 release](https://git.i3omb.com/gronod/ha-n95-local-control/src/tag/v0.1.2)
|
||
at commit `7bed99cc4c3222bad648efcddcdfed95652277f7`. See the
|
||
[tagged upstream README](https://git.i3omb.com/gronod/ha-n95-local-control/src/tag/v0.1.2/README.md)
|
||
for Docker Compose and direct Go-binary operation outside Home Assistant. The
|
||
upstream project is under the
|
||
[Apache License 2.0](https://git.i3omb.com/gronod/ha-n95-local-control/src/tag/v0.1.2/LICENCE.md).
|