Compare commits
2
Commits
c4095d0be7
...
97c0e4dc04
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97c0e4dc04 | ||
|
|
1a2a97babc |
@@ -8,6 +8,7 @@ Home Assistant custom add-on repository maintained by Gordon Bolton.
|
|||||||
|
|
||||||
| Add-on | Description | Documentation |
|
| Add-on | Description | Documentation |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| **Deebot N95 Local Control** | Local MQTT discovery and control for an already-provisioned Ecovacs Deebot N95 — replace its legacy cloud bootstrap and XMPP endpoint on a trusted LAN | [README](n95-mqtt-bridge/README.md) · [DOCS](n95-mqtt-bridge/DOCS.md) |
|
||||||
| **Emby MCP** | Emby Model Context Protocol server with a REST bridge — search and control an Emby media library from MCP clients and Home Assistant conversation agents | [README](emby-mcp/README.md) · [DOCS](emby-mcp/DOCS.md) |
|
| **Emby MCP** | Emby Model Context Protocol server with a REST bridge — search and control an Emby media library from MCP clients and Home Assistant conversation agents | [README](emby-mcp/README.md) · [DOCS](emby-mcp/DOCS.md) |
|
||||||
| **OpenAI Codex Proxy** | OpenAI-compatible local endpoint backed by a ChatGPT account (Codex OAuth) — use ChatGPT Plus/Pro models from OpenAI-compatible integrations | [README](openai-codex-proxy/README.md) · [DOCS](openai-codex-proxy/DOCS.md) |
|
| **OpenAI Codex Proxy** | OpenAI-compatible local endpoint backed by a ChatGPT account (Codex OAuth) — use ChatGPT Plus/Pro models from OpenAI-compatible integrations | [README](openai-codex-proxy/README.md) · [DOCS](openai-codex-proxy/DOCS.md) |
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
- Declare TCP 8007, 8005, 5223, and 8080 in the add-on `ports` map so
|
||||||
|
Home Assistant OS Supervisor opens those ports on the host firewall.
|
||||||
|
Host networking is unchanged; Docker does not remap the ports.
|
||||||
|
- Potential operational change: after update, the add-on Network tab
|
||||||
|
lists the four listeners. Rebuild/reinstall so HA picks up 0.1.1.
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
- First Home Assistant add-on release
|
||||||
|
- Build the upstream Deebot N95 bridge from the pinned `v0.1.0` tag
|
||||||
|
(`75354b35180f4cc5e92187b6149322b0b94533ba`)
|
||||||
|
- Bind robot-facing lookup, firmware, and XMPP listeners on the Home Assistant
|
||||||
|
host network
|
||||||
|
- Discover Supervisor MQTT connection details automatically with per-field
|
||||||
|
configuration overrides and external-broker support
|
||||||
|
- Expose the complete bridge configuration, with advanced and risky settings
|
||||||
|
hidden under optional configuration by default
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
# 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 |
|
||||||
|
| `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.
|
||||||
|
|
||||||
|
**The add-on reports an address-already-in-use error**
|
||||||
|
Another host service owns one of the four listener ports. 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.0 release](https://git.i3omb.com/gronod/ha-n95-local-control/src/tag/v0.1.0)
|
||||||
|
at commit `75354b35180f4cc5e92187b6149322b0b94533ba`. See the
|
||||||
|
[tagged upstream README](https://git.i3omb.com/gronod/ha-n95-local-control/src/tag/v0.1.0/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.0/LICENCE.md).
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
ARG GO_VERSION=1.27.1
|
||||||
|
ARG BUILD_FROM=ghcr.io/home-assistant/base:3.22
|
||||||
|
FROM golang:${GO_VERSION}-alpine AS build
|
||||||
|
|
||||||
|
RUN apk add --no-cache ca-certificates git
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
ARG UPSTREAM_REPOSITORY=https://git.i3omb.com/gronod/ha-n95-local-control.git
|
||||||
|
ARG UPSTREAM_REF=v0.1.0
|
||||||
|
ARG UPSTREAM_COMMIT=75354b35180f4cc5e92187b6149322b0b94533ba
|
||||||
|
RUN git init . \
|
||||||
|
&& git remote add origin "${UPSTREAM_REPOSITORY}" \
|
||||||
|
&& git fetch --depth 1 origin "refs/tags/${UPSTREAM_REF}:refs/tags/${UPSTREAM_REF}" \
|
||||||
|
&& test "$(git rev-list -n 1 "${UPSTREAM_REF}^{commit}")" = "${UPSTREAM_COMMIT}" \
|
||||||
|
&& git checkout --detach "${UPSTREAM_REF}^{commit}"
|
||||||
|
|
||||||
|
RUN go mod download
|
||||||
|
ARG TARGETOS=linux
|
||||||
|
ARG TARGETARCH
|
||||||
|
ARG TARGETVARIANT
|
||||||
|
RUN case "${TARGETARCH}/${TARGETVARIANT}" in \
|
||||||
|
amd64/) goarch=amd64; goarm= ;; \
|
||||||
|
arm64/) goarch=arm64; goarm= ;; \
|
||||||
|
386/) goarch=386; goarm= ;; \
|
||||||
|
arm/v6) goarch=arm; goarm=6 ;; \
|
||||||
|
arm/v7) goarch=arm; goarm=7 ;; \
|
||||||
|
*) echo "Unsupported target: ${TARGETARCH}/${TARGETVARIANT}" >&2; exit 1 ;; \
|
||||||
|
esac \
|
||||||
|
&& CGO_ENABLED=0 GOOS="${TARGETOS}" GOARCH="${goarch}" GOARM="${goarm}" \
|
||||||
|
go build -trimpath -ldflags="-s -w" -o /out/n95bridge ./cmd/n95bridge
|
||||||
|
|
||||||
|
FROM ${BUILD_FROM}
|
||||||
|
|
||||||
|
COPY --from=build /out/n95bridge /n95bridge
|
||||||
|
COPY rootfs /
|
||||||
|
RUN chmod a+x /run.sh
|
||||||
|
|
||||||
|
ARG BUILD_VERSION=0.1.1
|
||||||
|
ARG BUILD_ARCH
|
||||||
|
ARG UPSTREAM_REF=v0.1.0
|
||||||
|
ARG UPSTREAM_COMMIT=75354b35180f4cc5e92187b6149322b0b94533ba
|
||||||
|
LABEL \
|
||||||
|
io.hass.name="Deebot N95 Local Control" \
|
||||||
|
io.hass.description="Local MQTT control for an already-provisioned Deebot N95" \
|
||||||
|
io.hass.type="addon" \
|
||||||
|
io.hass.version="${BUILD_VERSION}" \
|
||||||
|
io.hass.arch="${BUILD_ARCH}" \
|
||||||
|
org.opencontainers.image.title="deebot-n95-local-control" \
|
||||||
|
org.opencontainers.image.source="https://git.i3omb.com/gronod/ha-gronod-addons" \
|
||||||
|
org.opencontainers.image.version="${BUILD_VERSION}" \
|
||||||
|
org.opencontainers.image.revision="${UPSTREAM_COMMIT}" \
|
||||||
|
com.gronod.upstream.ref="${UPSTREAM_REF}"
|
||||||
|
|
||||||
|
CMD [ "/run.sh" ]
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# Deebot N95 Local Control
|
||||||
|
|
||||||
|
<img src="logo.png" alt="Deebot N95 Local Control" width="128" height="128">
|
||||||
|
|
||||||
|
Redirect an already-provisioned Ecovacs Deebot N95 from its legacy cloud
|
||||||
|
bootstrap and XMPP endpoint to a local bridge, packaged as a Home Assistant
|
||||||
|
add-on.
|
||||||
|
|
||||||
|
The bridge publishes each robot through MQTT discovery as a native Home
|
||||||
|
Assistant vacuum. Once the LAN DNS redirect is in place, robot control and
|
||||||
|
state stay on your local network.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Local HTTP bootstrap and XMPP endpoint for compatible Deebot N95 robots
|
||||||
|
* Automatic Home Assistant MQTT vacuum discovery
|
||||||
|
* Multiple robots, with separate MQTT clients and topic trees by serial number
|
||||||
|
* Vacuum state and control, cleaning modes, movement, schedules, consumable
|
||||||
|
lifespan, and diagnostics
|
||||||
|
* Automatic Supervisor MQTT broker discovery with per-setting overrides
|
||||||
|
* Optional MQTT authentication, TLS, and private CA support
|
||||||
|
* Health endpoint for installation checks
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
* An already-provisioned Deebot N95 using the `wukong` / class `155` protocol
|
||||||
|
* Control of the DNS resolver supplied to the robot by DHCP
|
||||||
|
* A stable IPv4 address for the Home Assistant host
|
||||||
|
* TCP ports `8005`, `8007`, and `5223` reachable from the robot
|
||||||
|
* Home Assistant MQTT configured with discovery enabled, and a reachable broker
|
||||||
|
* The correct IANA timezone for the robot's clock and schedules
|
||||||
|
|
||||||
|
> The robot-facing XMPP connection, including SASL PLAIN authentication, is
|
||||||
|
> plaintext. Run this add-on only on a trusted LAN and restrict access to its
|
||||||
|
> listener ports. MQTT TLS protects the broker connection, not robot XMPP.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Add this repository to Home Assistant
|
||||||
|
(**Settings → Add-ons → Add-on Store → ⋮ → Repositories**):
|
||||||
|
`https://git.i3omb.com/gronod/ha-gronod-addons`
|
||||||
|
2. Install **Deebot N95 Local Control**
|
||||||
|
3. Set **Advertised IP address** to the stable LAN IPv4 address of the Home
|
||||||
|
Assistant host and select the correct timezone
|
||||||
|
4. Configure LAN DNS so `lbo.ecouser.net` resolves to that address
|
||||||
|
5. Start the add-on, verify its health and lookup endpoints, then reboot the
|
||||||
|
robot so it performs bootstrap again
|
||||||
|
|
||||||
|
See [DOCS.md](DOCS.md) for the complete network setup, option reference,
|
||||||
|
verification procedure, MQTT behavior, security notes, and troubleshooting.
|
||||||
|
|
||||||
|
## Upstream and license
|
||||||
|
|
||||||
|
The add-on builds
|
||||||
|
[ha-n95-local-control v0.1.0](https://git.i3omb.com/gronod/ha-n95-local-control/src/tag/v0.1.0),
|
||||||
|
which also contains standalone Docker and Go instructions. The upstream
|
||||||
|
software is licensed under the
|
||||||
|
[Apache License 2.0](https://git.i3omb.com/gronod/ha-n95-local-control/src/tag/v0.1.0/LICENCE.md).
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0.1.1
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
build_from:
|
||||||
|
aarch64: ghcr.io/home-assistant/aarch64-base:3.22
|
||||||
|
amd64: ghcr.io/home-assistant/amd64-base:3.22
|
||||||
|
armhf: ghcr.io/home-assistant/armhf-base:3.22
|
||||||
|
armv7: ghcr.io/home-assistant/armv7-base:3.22
|
||||||
|
i386: ghcr.io/home-assistant/i386-base:3.22
|
||||||
|
args:
|
||||||
|
GO_VERSION: "1.27.1"
|
||||||
|
UPSTREAM_REPOSITORY: "https://git.i3omb.com/gronod/ha-n95-local-control.git"
|
||||||
|
UPSTREAM_REF: "v0.1.0"
|
||||||
|
UPSTREAM_COMMIT: "75354b35180f4cc5e92187b6149322b0b94533ba"
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
name: "Deebot N95 Local Control"
|
||||||
|
description: >-
|
||||||
|
Redirect an already-provisioned Deebot N95 to local MQTT discovery and
|
||||||
|
control in Home Assistant.
|
||||||
|
version: "0.1.1"
|
||||||
|
slug: "n95_mqtt_bridge"
|
||||||
|
url: "https://git.i3omb.com/gronod/ha-gronod-addons/src/branch/main/n95-mqtt-bridge"
|
||||||
|
init: false
|
||||||
|
startup: application
|
||||||
|
boot: auto
|
||||||
|
host_network: true
|
||||||
|
ports:
|
||||||
|
8007/tcp: 8007
|
||||||
|
8005/tcp: 8005
|
||||||
|
5223/tcp: 5223
|
||||||
|
8080/tcp: 8080
|
||||||
|
ports_description:
|
||||||
|
8007/tcp: Robot bootstrap lookup
|
||||||
|
8005/tcp: Firmware check
|
||||||
|
5223/tcp: Robot XMPP
|
||||||
|
8080/tcp: Health
|
||||||
|
arch:
|
||||||
|
- aarch64
|
||||||
|
- amd64
|
||||||
|
- armhf
|
||||||
|
- armv7
|
||||||
|
- i386
|
||||||
|
services:
|
||||||
|
- mqtt:want
|
||||||
|
map:
|
||||||
|
- ssl
|
||||||
|
options:
|
||||||
|
advertise_ip: null
|
||||||
|
timezone: "Etc/UTC"
|
||||||
|
log_level: info
|
||||||
|
schema:
|
||||||
|
advertise_ip: str
|
||||||
|
timezone: str
|
||||||
|
log_level: list(debug|info|warn|error)
|
||||||
|
bind_address: str?
|
||||||
|
port_lookup: int?
|
||||||
|
port_firmware: int?
|
||||||
|
port_xmpp: int?
|
||||||
|
health_port: int?
|
||||||
|
mqtt_host: str?
|
||||||
|
mqtt_port: int?
|
||||||
|
mqtt_tls: bool?
|
||||||
|
mqtt_ca_file: str?
|
||||||
|
mqtt_username: str?
|
||||||
|
mqtt_password: password?
|
||||||
|
mqtt_client_id: str?
|
||||||
|
mqtt_base: str?
|
||||||
|
ha_discovery_prefix: str?
|
||||||
|
controller_jid: str?
|
||||||
|
raw_commands: bool?
|
||||||
|
panel_icon: mdi:robot-vacuum
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/with-contenv bashio
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
export ADVERTISE_IP="$(bashio::config 'advertise_ip')"
|
||||||
|
export TZ="$(bashio::config 'timezone')"
|
||||||
|
export LOG_LEVEL="$(bashio::config 'log_level')"
|
||||||
|
|
||||||
|
mqtt_source=""
|
||||||
|
if bashio::services.available "mqtt"; then
|
||||||
|
export MQTT_HOST="$(bashio::services mqtt 'host')"
|
||||||
|
export MQTT_PORT="$(bashio::services mqtt 'port')"
|
||||||
|
export MQTT_USERNAME="$(bashio::services mqtt 'username')"
|
||||||
|
export MQTT_PASSWORD="$(bashio::services mqtt 'password')"
|
||||||
|
export MQTT_TLS="$(bashio::services mqtt 'ssl')"
|
||||||
|
mqtt_source="Supervisor MQTT service"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export_option() {
|
||||||
|
local option="$1"
|
||||||
|
local variable="$2"
|
||||||
|
if bashio::config.exists "${option}"; then
|
||||||
|
export "${variable}=$(bashio::config "${option}")"
|
||||||
|
if [[ "${option}" == mqtt_* ]]; then
|
||||||
|
if [[ -n "${mqtt_source}" ]]; then
|
||||||
|
mqtt_source="${mqtt_source} with option overrides"
|
||||||
|
else
|
||||||
|
mqtt_source="add-on options"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
export_option bind_address BIND_ADDRESS
|
||||||
|
export_option port_lookup PORT_LOOKUP
|
||||||
|
export_option port_firmware PORT_FIRMWARE
|
||||||
|
export_option port_xmpp PORT_XMPP
|
||||||
|
export_option health_port HEALTH_PORT
|
||||||
|
export_option mqtt_host MQTT_HOST
|
||||||
|
export_option mqtt_port MQTT_PORT
|
||||||
|
export_option mqtt_tls MQTT_TLS
|
||||||
|
export_option mqtt_ca_file MQTT_CA_FILE
|
||||||
|
export_option mqtt_username MQTT_USERNAME
|
||||||
|
export_option mqtt_password MQTT_PASSWORD
|
||||||
|
export_option mqtt_client_id MQTT_CLIENT_ID
|
||||||
|
export_option mqtt_base MQTT_BASE
|
||||||
|
export_option ha_discovery_prefix HA_DISCOVERY_PREFIX
|
||||||
|
export_option controller_jid CONTROLLER_JID
|
||||||
|
export_option raw_commands RAW_COMMANDS
|
||||||
|
|
||||||
|
if [[ -z "${MQTT_HOST:-}" ]]; then
|
||||||
|
bashio::log.fatal "No MQTT broker is available. Configure a Supervisor MQTT service or set mqtt_host."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
bashio::log.info "Starting Deebot N95 Local Control"
|
||||||
|
bashio::log.info "Advertising ${ADVERTISE_IP}; MQTT settings from ${mqtt_source}"
|
||||||
|
if [[ "${RAW_COMMANDS:-false}" == "true" ]]; then
|
||||||
|
bashio::log.warning "Raw MQTT commands are enabled; use them only for protocol testing."
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec /n95bridge
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
configuration:
|
||||||
|
advertise_ip:
|
||||||
|
name: Advertised IP address
|
||||||
|
description: Stable Home Assistant host IPv4 address returned to the robot. Configure lbo.ecouser.net to resolve to this address.
|
||||||
|
timezone:
|
||||||
|
name: Time zone
|
||||||
|
description: IANA time zone used for the local time and UTC offset sent to the robot, for example Europe/London.
|
||||||
|
log_level:
|
||||||
|
name: Log level
|
||||||
|
description: Bridge log verbosity.
|
||||||
|
bind_address:
|
||||||
|
name: Bind address
|
||||||
|
description: Advanced. Address for all listeners. Keep 0.0.0.0 unless you have a specific host-network requirement.
|
||||||
|
port_lookup:
|
||||||
|
name: Lookup port
|
||||||
|
description: Advanced. Robot bootstrap HTTP port; defaults to 8007.
|
||||||
|
port_firmware:
|
||||||
|
name: Firmware port
|
||||||
|
description: Advanced. Robot firmware-check HTTP port; defaults to 8005.
|
||||||
|
port_xmpp:
|
||||||
|
name: XMPP port
|
||||||
|
description: Advanced. Plaintext robot XMPP port; defaults to 5223.
|
||||||
|
health_port:
|
||||||
|
name: Health port
|
||||||
|
description: Advanced. HTTP health endpoint port; defaults to 8080.
|
||||||
|
mqtt_host:
|
||||||
|
name: MQTT host
|
||||||
|
description: Broker host override without a scheme or port. The Supervisor MQTT service is used when available.
|
||||||
|
mqtt_port:
|
||||||
|
name: MQTT port
|
||||||
|
description: Broker port override. Defaults to 1883, or 8883 when TLS is enabled.
|
||||||
|
mqtt_tls:
|
||||||
|
name: MQTT TLS
|
||||||
|
description: Override whether the broker connection uses TLS with hostname verification.
|
||||||
|
mqtt_ca_file:
|
||||||
|
name: MQTT CA file
|
||||||
|
description: Optional PEM CA bundle inside the add-on, normally a path under /ssl.
|
||||||
|
mqtt_username:
|
||||||
|
name: MQTT username
|
||||||
|
description: Broker username override.
|
||||||
|
mqtt_password:
|
||||||
|
name: MQTT password
|
||||||
|
description: Broker password override. A nonempty password requires a username.
|
||||||
|
mqtt_client_id:
|
||||||
|
name: MQTT client ID prefix
|
||||||
|
description: Advanced. Prefix used for each robot's broker client ID.
|
||||||
|
mqtt_base:
|
||||||
|
name: MQTT base topic
|
||||||
|
description: Advanced. Single topic level before each robot serial; defaults to ecovacs.
|
||||||
|
ha_discovery_prefix:
|
||||||
|
name: Discovery prefix
|
||||||
|
description: Advanced. Home Assistant MQTT discovery prefix; defaults to homeassistant.
|
||||||
|
controller_jid:
|
||||||
|
name: Controller JID
|
||||||
|
description: Advanced. Virtual XMPP sender address presented to the robot.
|
||||||
|
raw_commands:
|
||||||
|
name: Raw commands
|
||||||
|
description: Advanced and risky. Allow protocol-level raw ctl commands over MQTT.
|
||||||
Reference in New Issue
Block a user