diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml deleted file mode 100644 index 4114b27f..00000000 --- a/.github/workflows/publish-to-pypi.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Publish releases to PyPI - -on: - release: - types: [published] - -jobs: - build-and-publish: - name: Builds and publishes releases to PyPI - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3.5.3 - - name: Get tag - id: vars - run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT - - name: Set up Python 3.10 - uses: actions/setup-python@v4.6.1 - with: - python-version: "3.10" - - name: Install build - run: >- - pip install build tomli tomli-w - - name: Set Python project version from tag - shell: python - run: |- - import tomli - import tomli_w - - with open("pyproject.toml", "rb") as f: - pyproject = tomli.load(f) - - pyproject["project"]["version"] = "${{ steps.vars.outputs.tag }}" - - with open("pyproject.toml", "wb") as f: - tomli_w.dump(pyproject, f) - - name: Build - run: >- - python3 -m build - - name: Publish release to PyPI - uses: pypa/gh-action-pypi-publish@v1.8.6 - with: - user: __token__ - password: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..fb440ade --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,84 @@ +name: Publish releases + +on: + release: + types: [published] + +jobs: + build-and-publish-pypi: + name: Builds and publishes releases to PyPI + runs-on: ubuntu-latest + outputs: + version: ${{ steps.vars.outputs.tag }} + steps: + - uses: actions/checkout@v3.5.3 + - name: Get tag + id: vars + run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT + - name: Set up Python 3.10 + uses: actions/setup-python@v4.6.1 + with: + python-version: "3.10" + - name: Install build + run: >- + pip install build tomli tomli-w + - name: Set Python project version from tag + shell: python + run: |- + import tomli + import tomli_w + + with open("pyproject.toml", "rb") as f: + pyproject = tomli.load(f) + + pyproject["project"]["version"] = "${{ steps.vars.outputs.tag }}" + + with open("pyproject.toml", "wb") as f: + tomli_w.dump(pyproject, f) + - name: Build + run: >- + python3 -m build + - name: Publish release to PyPI + uses: pypa/gh-action-pypi-publish@v1.8.6 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} + repository-url: https://test.pypi.org/legacy/ + build-and-push-container-image: + name: Builds and pushes the Matter Server container to ghcr.io + runs-on: ubuntu-latest + permissions: + packages: write + needs: build-and-publish-pypi + steps: + - uses: actions/checkout@v3.5.3 + - name: Log in to the GitHub container registry + uses: docker/login-action@v2.1.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2.2.1 + - name: Version number for tags + id: tags + shell: bash + run: |- + patch=${GITHUB_REF#refs/*/} + echo "patch=${patch}" >> $GITHUB_OUTPUT + echo "minor=${patch%.*}" >> $GITHUB_OUTPUT + echo "major=${patch%.*.*}" >> $GITHUB_OUTPUT + - name: Build and Push + uses: docker/build-push-action@v3.3.0 + with: + context: . + platforms: linux/amd64,linux/arm64 + file: Dockerfile + tags: |- + ghcr.io/${{ github.repository_owner }}/python-matter-server:${{ steps.tags.outputs.patch }}, + ghcr.io/${{ github.repository_owner }}/python-matter-server:${{ steps.tags.outputs.minor }}, + ghcr.io/${{ github.repository_owner }}/python-matter-server:${{ steps.tags.outputs.major }}, + ghcr.io/${{ github.repository_owner }}/python-matter-server:stable + push: true + build-args: + "PYTHON_MATTER_SERVER=${{ needs.build-and-publish-pypi.outputs.version }}" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..fd1450b9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +FROM python:3.11-slim-bullseye + +# Set shell +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +WORKDIR /app + +RUN \ + set -x \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libuv1 \ + openssl \ + zlib1g \ + libjson-c5 \ + libnl-3-200 \ + libnl-route-3-200 \ + unzip \ + gdb \ + && apt-get purge -y --auto-remove \ + && rm -rf \ + /var/lib/apt/lists/* \ + /usr/src/* + +ARG PYTHON_MATTER_SERVER + +# hadolint ignore=DL3013 +RUN \ + pip3 install --no-cache-dir "python-matter-server[server]==${PYTHON_MATTER_SERVER}" + +VOLUME ["/data"] +EXPOSE 5580 + +ENTRYPOINT ["matter-server", "--storage-path", "/data"] diff --git a/README.md b/README.md index 750b87bb..12d93f30 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,118 @@ # Python Matter Server -This project implements a Matter Controller Server over WebSockets using the [official Matter (formerly CHIP) SDK](https://github.com/project-chip/connectedhomeip) as a base and provides both a server and client implementation. +This project implements a Matter Controller Server over WebSockets using the +[official Matter (formerly CHIP) SDK](https://github.com/project-chip/connectedhomeip) +as a base and provides both a server and client implementation. -The goal of this project is primary to have Matter support in Home Assistant but its universal approach makes it suitable to be used in other projects too. +The goal of this project is primary to have Matter support in Home Assistant +but its universal approach makes it suitable to be used in other projects too. -This repository is for development only (so not for enduser support). For enabling Matter support within Home Assistant, please refer to the [Home Assistant documentation](https://www.home-assistant.io/integrations/matter/). +## Support + +Got questions? + +You have several options to get them answered: + + * The Home Assistant [Community Forum](https://community.home-assistant.io/). + * The Home Assistant [Discord Chat Server](https://discord.gg/c5DvZ4e). + * Join [the Reddit subreddit in /r/homeassistant](https://reddit.com/r/homeassistant). + +If you experience issues using Matter with Home Assistant, please open an issue +report in the [Home Assistant Core repository](https://github.com/home-assistant/core/issues/new/choose). + +You may also open issues in this repository if you are absolutely sure that your +issue is related to the Matter Server component. + +## Installation + +We strongly recommend to use Home Assistant OS along with the official Matter +Server add-on to use Matter with Home Assistant. The Matter integration +automatically installs the Python Matter Server add-on. Please refer to the +[Home Assistant documentation](https://www.home-assistant.io/integrations/matter/). +Home Assistant OS has been tested and tuned to be used with Matter and Thead, +which makes this combination the best tested and largely worry free +environment. + +If you still prefer a self-managed container installation, we do offer an +official container image. Please keep in mind that you might experience +communication issues with Matter devices, especially Thread based devices. +This is mostly because the container installation uses host networking, and +relies on the networking managed by your operating system. + +### Requirements to communicate with Wi-Fi/Ethernet based Thread devices + +Make sure your you run the container on the host network. The host network +interface needs to be in the same network as the Android/iPhone device +you are using for commissioning. Matter uses link-local multicast protocols +which do not work accross different LANs or VLANs. + +The host network interface needs IPv6 support enabled. + +### Requirements to communicate with Thread devices through Thread border routers + +For communication through Thread border routers which are not running on the same +host as the Matter Controller server to work, IPv6 routing needs to be properly +working. IPv6 routing is largely setup automatically through the IPv6 Neighbor +Discovery Protocol, specifically the Route Information Options (RIO). However, +if IPv6 ND RIO's are processed, and processed correctly depends on the network +management software your system is using. There may be bugs and cavats in +processing this Route Information Options. + +In general, make sure the kernel option `CONFIG_IPV6_ROUTER_PREF` is enabled and +that IPv6 forwarding is disabled (sysctl variable `net.ipv6.conf.all.forwarding`). +If IPv6 forwarding is enabled, the Linux kernel doesn't employ reachability +probing (RFC 4191), which can lead to longer outages (up to 30min) until +network changes are detected. + +If you are using NetworkManager, make sure to use at least NetworkManager 1.42. +Previous versions lose track of routes and stale routes can lead to unreachable +Thread devices. All current released NetworkManager versions can't handle +multiple routes to the same network properly. This means if you have multiple +Thread border routers, the fallback won't work immediately (see [NetworkManager +issue #1232](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1232)). + +We currently don't have experience with systemd-networkd. It seems to have its +own IPv6 Neighbor Discovery Protocol handling. + +If you don't use NetworkManager or systemd-networkd, you can use the kernel's +IPv6 Neighbor Discovery Protocol handling. + +Make sure the kernel options `CONFIG_IPV6_ROUTE_INFO` is enabled and the +following sysctl variables are set: + +``` +sysctl -w net.ipv6.conf.wlan0.accept_ra=1 +sysctl -w net.ipv6.conf.wlan0.accept_ra_rt_info_max_plen=64 +``` + +If your system has IPv6 forwarding enabled (not recommended, see above), you'll +have to use `2` for the accept_ra variable. See also the [Thread Border Router - Bidirectional IPv6 Connectivity and DNS-Based Service Discovery codelab](https://openthread.io/codelabs/openthread-border-router#6). + +### Running the Matter Server using container image + +With the following command you can run the Matter Server in a container using +Docker. The Matter network data (fabric information) are stored in a newly +created directory `data` in the current directory. Adjust the command to +choose another location instead. + +``` +mkdir data +docker run -d \ + --name matter-server \ + --restart=unless-stopped \ + --security-opt apparmor=unconfined \ + -v $(pwd)/data:/data \ + -v /run/dbus:/run/dbus:ro \ + --network=host \ + ghcr.io/home-assistant-libs/python-matter-server:stable +``` + +### Running using Docker compose + +```sh +docker compose up -d +docker compose logs -f +``` NOTE: Both Matter and this implementation are in early (v1) state and features are probably missing or could be improved. See our [development notes](#development) how you can help out, with development and/or testing. diff --git a/compose.yml b/compose.yml index 7d3dd647..b89d9ab1 100644 --- a/compose.yml +++ b/compose.yml @@ -2,9 +2,6 @@ version: "3.8" services: # python-matter-server matter-server: - build: - context: ./ - dockerfile: Dockerfile.dev image: matter-server:latest container_name: matter-server restart: unless-stopped