├── .gitignore ├── rootfs ├── etc │ ├── s6-overlay │ │ ├── s6-rc.d │ │ │ ├── cpcd │ │ │ │ ├── type │ │ │ │ ├── notification-fd │ │ │ │ ├── dependencies.d │ │ │ │ │ ├── legacy-cont-init │ │ │ │ │ └── universal-silabs-flasher │ │ │ │ ├── data │ │ │ │ │ └── check │ │ │ │ ├── run │ │ │ │ └── finish │ │ │ ├── mdns │ │ │ │ ├── type │ │ │ │ ├── finish │ │ │ │ └── run │ │ │ ├── user │ │ │ │ └── contents.d │ │ │ │ │ ├── cpcd │ │ │ │ │ ├── mdns │ │ │ │ │ ├── zigbeed │ │ │ │ │ └── otbr-agent │ │ │ ├── otbr-agent │ │ │ │ ├── type │ │ │ │ ├── dependencies.d │ │ │ │ │ └── cpcd │ │ │ │ ├── notification-fd │ │ │ │ ├── data │ │ │ │ │ └── check │ │ │ │ ├── finish │ │ │ │ └── run │ │ │ ├── otbr-web │ │ │ │ ├── type │ │ │ │ ├── dependencies.d │ │ │ │ │ └── otbr-agent │ │ │ │ ├── finish │ │ │ │ └── run │ │ │ ├── zigbeed │ │ │ │ ├── dependencies.d │ │ │ │ │ └── cpcd │ │ │ │ ├── type │ │ │ │ ├── finish │ │ │ │ └── run │ │ │ ├── socat-cpcd-tcp │ │ │ │ ├── type │ │ │ │ ├── notification-fd │ │ │ │ ├── data │ │ │ │ │ └── check │ │ │ │ └── run │ │ │ └── universal-silabs-flasher │ │ │ │ ├── type │ │ │ │ ├── notification-fd │ │ │ │ └── up │ │ └── scripts │ │ │ ├── enable-check.sh │ │ │ ├── otbr-agent-common │ │ │ ├── socat-cpcd-tcp-enable-check.sh │ │ │ ├── otbr-enable-check.sh │ │ │ └── universal-silabs-flasher-up │ ├── cont-init.d │ │ ├── check-cpcd-shm.sh │ │ └── config.sh │ └── bashlog │ │ └── log.sh └── usr │ └── local │ └── share │ └── cpcd.conf ├── BASE.md ├── DOCS.md ├── CHANGELOG.md ├── VERSIONS.md ├── .github └── workflows │ ├── cleanup.yml │ ├── build_all.yml │ ├── build_latest.yml │ └── build_version.yml ├── .run └── local-test.run.xml ├── docker-compose.yml ├── Dockerfile ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .env 3 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/cpcd/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/mdns/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/cpcd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/mdns: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/zigbeed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/cpcd/notification-fd: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-web/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/otbr-agent: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/zigbeed/dependencies.d/cpcd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/zigbeed/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/dependencies.d/cpcd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/notification-fd: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/socat-cpcd-tcp/type: -------------------------------------------------------------------------------- 1 | longrun 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-web/dependencies.d/otbr-agent: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/socat-cpcd-tcp/notification-fd: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/cpcd/dependencies.d/legacy-cont-init: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/universal-silabs-flasher/type: -------------------------------------------------------------------------------- 1 | oneshot 2 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/cpcd/dependencies.d/universal-silabs-flasher: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/universal-silabs-flasher/notification-fd: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /BASE.md: -------------------------------------------------------------------------------- 1 | # Base 2 | 3 | https://github.com/home-assistant/addons/tree/master/silabs-multiprotocol -------------------------------------------------------------------------------- /DOCS.md: -------------------------------------------------------------------------------- 1 | # Docs 2 | 3 | https://github.com/home-assistant/addons/blob/master/silabs-multiprotocol/DOCS.md -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/socat-cpcd-tcp/data/check: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | test -c /tmp/ttyCPC 4 | exit 5 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/universal-silabs-flasher/up: -------------------------------------------------------------------------------- 1 | /etc/s6-overlay/scripts/universal-silabs-flasher-up 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | https://github.com/home-assistant/addons/blob/master/silabs-multiprotocol/CHANGELOG.md -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/cpcd/data/check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if CPC daemon socket exists 4 | test -S /dev/shm/cpcd/cpcd_0/ctrl.cpcd.sock 5 | exit 6 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/scripts/enable-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /etc/s6-overlay/scripts/otbr-enable-check.sh 4 | /etc/s6-overlay/scripts/socat-cpcd-tcp-enable-check.sh 5 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/data/check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if openthread socket exists 4 | mapfile -t < /tmp/otbr-agent-rest-api 5 | test -S /run/openthread-wpan0.sock && nc -z "${MAPFILE[@]}" 6 | exit 7 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/scripts/otbr-agent-common: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | declare thread_if 4 | declare otbr_forward_ingress_chain 5 | declare otbr_forward_egress_chain 6 | thread_if="wpan0" 7 | otbr_forward_ingress_chain="OTBR_FORWARD_INGRESS" 8 | otbr_forward_egress_chain="OTBR_FORWARD_EGRESS" 9 | 10 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/mdns/finish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | #============================================================================== 3 | # mDNSResponder finish script 4 | #============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "mDNS ended with exit code ${1} (signal ${2})..." 8 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/zigbeed/finish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | #============================================================================== 3 | # EmberZNet Zigbee Daemon finish script 4 | #============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "zigbeed ended with exit code ${1} (signal ${2})..." 8 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-web/finish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | #============================================================================== 3 | # OpenThread BorderRouter web interface finish script 4 | #============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "otbr-web ended with exit code ${1} (signal ${2})..." 8 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/check-cpcd-shm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Check that no other CPC instance is running on this system 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | if test -d /dev/shm/cpcd; then 8 | log 'info' "Another CPC daemon running!" 9 | exit 1 10 | fi 11 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/cpcd/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Start Co-Processor Communication Daemon (CPCd) 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "Starting cpcd..." 8 | exec s6-notifyoncheck -d -s 300 -w 300 -n 0 \ 9 | "/usr/bin/stdbuf" -o0 /usr/local/bin/cpcd 10 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-web/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Start OpenThread BorderRouter web interface 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "Starting otbr-web..." 8 | declare otbr_web_port 9 | 10 | otbr_web_port=$OTBR_WEB_PORT 11 | 12 | exec /usr/sbin/otbr-web -I wpan0 -d6 -p "${otbr_web_port}" 13 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/cpcd/finish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Take down the container if cpcd exits 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "CPC ended with exit code ${1} (signal ${2})..." 8 | rm -r /dev/shm/cpcd 9 | 10 | 11 | if [ ${1} -ne 0 ] && [ ${1} -ne 256 ]; then 12 | /run/s6/basedir/bin/halt 13 | fi 14 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/mdns/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Start mDNSResponder daemon 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "Starting mDNS Responder..." 8 | 9 | # mdnsd runs as daemon except when using debug mode. We prefer non-daemon, so 10 | # start in debug by default. It seems nto to generate a vast amount of 11 | # messages. 12 | exec /usr/sbin/mdnsd -debug 13 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/scripts/socat-cpcd-tcp-enable-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Enable socat-cpcd-tcp service if needed 4 | # ============================================================================== 5 | 6 | # if bashio::config.has_value 'network_device'; then 7 | # touch /etc/s6-overlay/s6-rc.d/user/contents.d/socat-cpcd-tcp 8 | # touch /etc/s6-overlay/s6-rc.d/cpcd/dependencies.d/socat-cpcd-tcp 9 | # bashio::log.info "Enabled socat-cpcd-tcp." 10 | # fi 11 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/socat-cpcd-tcp/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Start socat TCP client for CPC daemon 4 | # ============================================================================== 5 | 6 | declare network_device 7 | 8 | network_device=$NETWORK_DEVICE 9 | 10 | # echo "Starting socat TCP client for CPC daemon..." 11 | # exec s6-notifyoncheck -d -s 300 -w 300 \ 12 | # "/usr/bin/socat" -d pty,raw,echo=0,link=/tmp/ttyCPC,ignoreeof \ 13 | # "tcp:${network_device}" 14 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/scripts/otbr-enable-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Disable OTBR if not enabled 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | if [ $OTBR_ENABLE -eq 0 ]; then 8 | rm /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-agent 9 | rm /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-web 10 | log 'info' "The otbr-agent is disabled." 11 | else 12 | log 'info' "Web UI and REST API port are exposed, starting otbr-web." 13 | fi 14 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/zigbeed/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Start EmberZNet Zigbee Daemon 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | mkdir -p /data/zigbeed && cd /data/zigbeed || log 'error' "Could not change to zigbeed working directory" 8 | 9 | log 'info' "Starting zigbeed..." 10 | exec /usr/local/bin/zigbeed --radio-url "spinel+cpc://cpcd_0?iid=1&iid-list=0" \ 11 | --ezsp-listen "::" \ 12 | --ezsp-listen-port ${EZSP_LISTEN_PORT} 13 | -------------------------------------------------------------------------------- /VERSIONS.md: -------------------------------------------------------------------------------- 1 | # Versions 2 | 3 | known working combinations of firmware and container versions 4 | 5 | | container | SkyConnect | sonoff | | | 6 | |-----------|--------------------------------------------------------------|--------|---|---| 7 | | 2.4.5 | NabuCasa_SkyConnect_RCP_v4.3.2_rcp-uart-hw-802154_460800.gbl | | | | 8 | | 2.4.4 | NabuCasa_SkyConnect_RCP_v4.3.1_rcp-uart-hw-802154_460800.gbl | | | | 9 | | 2.4.3 | NabuCasa_SkyConnect_RCP_v4.4.0_rcp-uart-hw-802154_460800.gbl | | | | 10 | | 2.4.2 | NabuCasa_SkyConnect_RCP_v4.3.1_rcp-uart-hw-802154_460800.gbl | | | | 11 | -------------------------------------------------------------------------------- /.github/workflows/cleanup.yml: -------------------------------------------------------------------------------- 1 | name: 'cleanup' 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '0 0 1 * *' 6 | 7 | jobs: 8 | clean_workflow_runs: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | actions: write 12 | steps: 13 | - name: clean workflow runs 14 | uses: Mattraks/delete-workflow-runs@v2 15 | with: 16 | token: ${{ github.token }} 17 | repository: ${{ github.repository }} 18 | retain_days: 30 19 | keep_minimum_runs: 30 20 | 21 | remove_package_versions: 22 | runs-on: ubuntu-latest 23 | permissions: write-all 24 | steps: 25 | - name: purge container packages 26 | uses: dylanratcliffe/delete-untagged-containers@main 27 | with: 28 | package_name: 'silabs-multipan-docker' 29 | token: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /.run/local-test.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 14 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/scripts/universal-silabs-flasher-up: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Start universal-silabs-flasher if requested 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | if [ $AUTOFLASH_FIRMWARE -eq 0 ]; then 8 | log 'info' "Flashing firmware is disabled" 9 | exit 0 10 | fi 11 | 12 | if [[ -z "${FIRMWARE}" ]]; then 13 | log 'info' "No firmware found for the selected device, assuming firmware is installed." 14 | exit 0 15 | fi 16 | 17 | # All firmware we flash have a known baudrate of 460800, let cpcd know. 18 | echo 460800 > /tmp/known-baudrate 19 | 20 | log 'info' "Starting universal-silabs-flasher with ${DEVICE} (baudrate ${BAUDRATE})" 21 | exec universal-silabs-flasher --device ${DEVICE} \ 22 | flash --ensure-exact-version --allow-cross-flashing --firmware "/data/firmware/${FIRMWARE}" -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | multipan: 4 | container_name: multipan 5 | image: b2un0/silabs-multipan-docker:latest 6 | restart: unless-stopped 7 | privileged: true # don't change this ! 8 | network_mode: host # don't change this ! 9 | cap_add: 10 | - SYS_ADMIN 11 | - NET_ADMIN 12 | volumes: 13 | - ~/multipan/:/data 14 | environment: 15 | DEVICE: "/dev/ttyUSB0" # only change if your have multiple devices 16 | BAUDRATE: "460800" 17 | FLOW_CONTROL: "true" # change to false if you not using SkyConnect 18 | 19 | BACKBONE_IF: "eth0" # change this to your network interface 20 | OTBR_REST_LISTEN_PORT: "8081" # use this within the HomeAssistant integration 21 | OTBR_WEB_PORT: "8086" 22 | 23 | # ZIGBEED environment variables 24 | EZSP_LISTEN_PORT: "20108" # 25 | 26 | # UNIVERSAL FLASHER variables 27 | AUTOFLASH_FIRMWARE: 0 # change to 1 for firmware update 28 | FIRMWARE: "NabuCasa_SkyConnect_RCP_v4.3.1_rcp-uart-hw-802154_460800.gbl" 29 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_VERSION 2 | FROM homeassistant/${TARGETARCH}-addon-silabs-multiprotocol:${BASE_VERSION} 3 | 4 | ENV S6_VERBOSITY=3 \ 5 | DEVICE="/dev/ttyUSB0" \ 6 | BAUDRATE="460800" \ 7 | CPCD_TRACE="false" \ 8 | CPCP_DISABLE_ENCRYPTION="true" \ 9 | FLOW_CONTROL="true" \ 10 | NETWORK_DEVICES=0 \ 11 | OTBR_ENABLE=1 \ 12 | BACKBONE_IF="eth0" \ 13 | OTBR_LOG_LEVEL="notice" \ 14 | OTB_FIREWALL=1 \ 15 | OTBR_REST_LISTEN_PORT="8081" \ 16 | OTBR_WEB_PORT="8086" \ 17 | NETWORK_DEVICE="" \ 18 | EZSP_LISTEN_PORT="20108"\ 19 | AUTOFLASH_FIRMWARE=0 \ 20 | FIRMWARE="" 21 | 22 | RUN rm -rf /etc/s6-overlay/s6-rc.d/banner && \ 23 | rm -rf /etc/s6-overlay/scripts/banner.sh && \ 24 | rm -rf /etc/s6-overlay/s6-rc.d/universal-silabs-flasher/dependencies.d && \ 25 | rm -rf /etc/s6-overlay/s6-rc.d/otbr-agent-rest-discovery && \ 26 | rm -rf /etc/s6-overlay/scripts/otbr-agent-rest-discovery.sh && \ 27 | rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/otbr-agent-rest-discovery && \ 28 | rm -rf /etc/s6-overlay/s6-rc.d/cpcd-config && \ 29 | rm -rf /etc/s6-overlay/s6-rc.d/cpcd/dependencies.d && \ 30 | rm -rf /usr/bin/bashio && \ 31 | rm -rf *.gbl && \ 32 | rm -rf firmware && \ 33 | rm -rf /home/firmware && \ 34 | rm -rf /root/*.gbl 35 | 36 | COPY rootfs / 37 | 38 | WORKDIR / 39 | 40 | VOLUME /data 41 | 42 | ENTRYPOINT ["/init"] 43 | -------------------------------------------------------------------------------- /.github/workflows/build_all.yml: -------------------------------------------------------------------------------- 1 | name: 'build all' 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | REPO_URL: "https://registry.hub.docker.com/v2/namespaces/homeassistant/repositories/amd64-addon-silabs-multiprotocol/tags?page=1&page_size=1000" 8 | 9 | jobs: 10 | provide_versions: 11 | name: provide base versions 12 | runs-on: ubuntu-latest 13 | outputs: 14 | matrix: ${{ steps.tags.outputs.matrix }} 15 | steps: 16 | - name: get all tags 17 | id: tags 18 | run: echo matrix=$(curl -s '${{ env.REPO_URL }}' | jq -r '.results | reverse') >> $GITHUB_OUTPUT 19 | - name: count tags 20 | run: jq -r 'length' <<< '${{ steps.tags.outputs.matrix }}' 21 | 22 | run_builds: 23 | runs-on: ubuntu-latest 24 | needs: provide_versions 25 | permissions: write-all 26 | strategy: 27 | max-parallel: 1 28 | matrix: 29 | include: ${{ fromJson(needs.provide_versions.outputs.matrix) }} 30 | name: trigger build for ${{ fromJSON(toJSON(matrix)).name }} 31 | steps: 32 | - name: Check 33 | env: 34 | VERSION: ${{ fromJSON(toJSON(matrix)).name }} 35 | run: | 36 | echo "VERSION: ${{ env.VERSION }}" 37 | 38 | - name: Repository Dispatch 39 | uses: peter-evans/repository-dispatch@v2 40 | with: 41 | event-type: build_version 42 | client-payload: '{"base_version": "${{ fromJSON(toJSON(matrix)).name }}"}' 43 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/config.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # Generate Silicon Labs Multiprotocol configurations 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | if [[ -z "${DEVICE}" ]]; then 8 | log 'error' "No serial port device set!" 9 | exit 1 10 | fi 11 | 12 | if [ $NETWORK_DEVICES -eq 1 ]; then 13 | export DEVICE="/tmp/ttyCPC" 14 | fi 15 | 16 | if [[ -z "${BAUDRATE}" ]]; then 17 | log 'error' "No serial port baudrate set!" 18 | exit 1 19 | fi 20 | 21 | if [[ -z "${FLOW_CONTROL}" ]]; then 22 | export FLOW_CONTROL="false" 23 | fi 24 | 25 | if [[ -z "${CPCD_TRACE}" ]]; then 26 | export CPCD_TRACE="false" 27 | fi 28 | 29 | if [[ -z "${CPCP_DISABLE_ENCRYPTION}" ]]; then 30 | export CPCP_DISABLE_ENCRYPTION="false" 31 | fi 32 | 33 | log 'info' "\n######### ENV ######" 34 | env 35 | 36 | log 'info' "Generating cpcd configuration." 37 | sed -i 's@{{ .device }}@'"$DEVICE"'@' /usr/local/share/cpcd.conf 38 | sed -i 's@{{ .baudrate }}@'"$BAUDRATE"'@' /usr/local/share/cpcd.conf 39 | sed -i 's@{{ .cpcd_trace }}@'"$CPCD_TRACE"'@' /usr/local/share/cpcd.conf 40 | sed -i 's@{{ .flow_control }}@'"$FLOW_CONTROL"'@' /usr/local/share/cpcd.conf 41 | sed -i 's@{{ .disable_encryption }}@'"$CPCP_DISABLE_ENCRYPTION"'@' /usr/local/share/cpcd.conf 42 | sed -i 's@binding_key_file@'"#binding_key_file"'@' /usr/local/share/cpcd.conf 43 | cp /usr/local/share/cpcd.conf /usr/local/etc/cpcd.conf 44 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/finish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | #============================================================================== 3 | # OpenThread BorderRouter Daemon finish script 4 | #============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | log 'info' "otbr-agent ended with exit code ${1} (signal ${2})..." 8 | 9 | 10 | . /etc/s6-overlay/scripts/otbr-agent-common 11 | 12 | ipset_destroy_if_exist() 13 | { 14 | # The ipset seems to be in use by the kernel for a brief period, 15 | # retry destroying it 16 | while ipset list -n "$1" 2> /dev/null; do 17 | ipset destroy "$1" || true 18 | done 19 | } 20 | 21 | while ip6tables -C FORWARD -o $thread_if -j $otbr_forward_ingress_chain 2> /dev/null; do 22 | ip6tables -D FORWARD -o $thread_if -j $otbr_forward_ingress_chain 23 | done 24 | 25 | if ip6tables -L $otbr_forward_ingress_chain 2> /dev/null; then 26 | ip6tables -w -F $otbr_forward_ingress_chain 27 | ip6tables -w -X $otbr_forward_ingress_chain 28 | fi 29 | 30 | ipset_destroy_if_exist otbr-ingress-deny-src 31 | ipset_destroy_if_exist otbr-ingress-deny-src-swap 32 | ipset_destroy_if_exist otbr-ingress-allow-dst 33 | ipset_destroy_if_exist otbr-ingress-allow-dst-swap 34 | 35 | while ip6tables -C FORWARD -i $thread_if -j $otbr_forward_egress_chain 2> /dev/null; do 36 | ip6tables -D FORWARD -i $thread_if -j $otbr_forward_egress_chain 37 | done 38 | 39 | if ip6tables -L $otbr_forward_egress_chain 2> /dev/null; then 40 | ip6tables -w -F $otbr_forward_egress_chain 41 | ip6tables -w -X $otbr_forward_egress_chain 42 | fi 43 | log 'info' "OTBR firewall teardown completed." 44 | 45 | if test "$1" -eq 256 ; then 46 | e=$((128 + $2)) 47 | else 48 | e="$1" 49 | fi 50 | 51 | log 'info' "$e" > /run/s6-linux-init-container-results/exitcode 52 | -------------------------------------------------------------------------------- /.github/workflows/build_latest.yml: -------------------------------------------------------------------------------- 1 | name: 'build latest' 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 0 * * *' 7 | 8 | jobs: 9 | get_versions: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | base_version: ${{ steps.base_version.outputs.base_version }} 13 | self_version: ${{ steps.self_version.outputs.self_version }} 14 | steps: 15 | - name: base version 16 | id: base_version 17 | run: | 18 | docker pull homeassistant/amd64-addon-silabs-multiprotocol:latest 19 | echo base_version=$(docker inspect homeassistant/amd64-addon-silabs-multiprotocol:latest --format '{{ index .Config.Labels "org.opencontainers.image.version"}}') >> $GITHUB_OUTPUT 20 | 21 | - name: show base version 22 | run: | 23 | echo ${{ steps.base_version.outputs.base_version }} 24 | 25 | - name: self version 26 | id: self_version 27 | run: | 28 | docker pull b2un0/silabs-multipan-docker:latest 29 | echo self_version=$(docker inspect b2un0/silabs-multipan-docker:latest --format '{{ index .Config.Labels "org.opencontainers.image.version"}}') >> $GITHUB_OUTPUT 30 | 31 | - name: show self version 32 | run: | 33 | echo ${{ steps.self_version.outputs.self_version }} 34 | 35 | trigger_build: 36 | runs-on: ubuntu-latest 37 | needs: get_versions 38 | permissions: write-all 39 | name: trigger build for ${{ needs.get_versions.outputs.base_version }} 40 | if: needs.get_versions.outputs.base_version != needs.get_versions.outputs.self_version || github.event_name == 'workflow_dispatch' 41 | steps: 42 | - name: Repository Dispatch 43 | uses: peter-evans/repository-dispatch@v2 44 | with: 45 | event-type: build_version 46 | client-payload: '{"base_version": "${{ needs.get_versions.outputs.base_version }}", "is_latest": "yes"}' 47 | -------------------------------------------------------------------------------- /.github/workflows/build_version.yml: -------------------------------------------------------------------------------- 1 | name: 'build for version' 2 | run-name: 'build for version ${{ inputs.base_version }}${{ github.event.client_payload.base_version }}' 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | base_version: 8 | description: 'base version' 9 | required: true 10 | default: 'x.x.x' 11 | repository_dispatch: 12 | types: [build_version] 13 | 14 | jobs: 15 | build_version: 16 | runs-on: ubuntu-latest 17 | permissions: write-all 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | 22 | - name: set version 23 | run: echo "BASE_VERSION=${{ inputs.base_version }}${{ github.event.client_payload.base_version }}" >> $GITHUB_ENV 24 | 25 | - name: Login to DockerHub 26 | uses: docker/login-action@v3 27 | with: 28 | username: ${{ vars.DOCKER_USERNAME }} 29 | password: ${{ secrets.DOCKER_TOKEN }} 30 | 31 | - name: Login to ghcr.io 32 | uses: docker/login-action@v3 33 | with: 34 | registry: ghcr.io 35 | username: ${{ github.repository_owner }} 36 | password: ${{ secrets.GITHUB_TOKEN }} 37 | 38 | - name: Docker meta 39 | id: meta 40 | uses: docker/metadata-action@v5 41 | with: 42 | images: ${{ vars.DOCKER_USERNAME }}/${{ vars.DOCKER_IMAGE }},ghcr.io/${{ github.repository }} 43 | tags: | 44 | type=raw,value=${{ env.BASE_VERSION }} 45 | type=raw,value=latest,enable=${{ github.event.client_payload.is_latest == 'yes' }} 46 | 47 | - name: Set up QEMU 48 | uses: docker/setup-qemu-action@v3 49 | 50 | - name: Set up Docker Buildx 51 | uses: docker/setup-buildx-action@v3 52 | 53 | - name: Build and push 54 | uses: docker/build-push-action@v5 55 | with: 56 | context: . 57 | # create an alias for arm64 (TARGETARCH in build arg) from the existing aarch64 image 58 | # create an alias for arm (TARGETARCH in build arg) from the existing armv7 image 59 | build-contexts: | 60 | homeassistant/arm64-addon-silabs-multiprotocol:latest=docker-image://docker.io/homeassistant/aarch64-addon-silabs-multiprotocol:latest 61 | homeassistant/arm-addon-silabs-multiprotocol:latest=docker-image://docker.io/homeassistant/armv7-addon-silabs-multiprotocol:latest 62 | homeassistant/arm64-addon-silabs-multiprotocol:${{ env.BASE_VERSION }}=docker-image://docker.io/homeassistant/aarch64-addon-silabs-multiprotocol:${{ env.BASE_VERSION }} 63 | homeassistant/arm-addon-silabs-multiprotocol:${{ env.BASE_VERSION }}=docker-image://docker.io/homeassistant/armv7-addon-silabs-multiprotocol:${{ env.BASE_VERSION }} 64 | platforms: linux/amd64,linux/arm64,linux/arm/v7 65 | push: true 66 | tags: ${{ steps.meta.outputs.tags }} 67 | labels: ${{ steps.meta.outputs.labels }} 68 | provenance: false 69 | build-args: | 70 | BASE_VERSION=${{ env.BASE_VERSION }} 71 | -------------------------------------------------------------------------------- /rootfs/usr/local/share/cpcd.conf: -------------------------------------------------------------------------------- 1 | # Instance Name 2 | # Optional, defaults to "cpcd_0" 3 | # This string uniquely identifies the running cpcd instance. 4 | # An application must pass this value to cpc_init() to connect 5 | # to this particular instance. 6 | instance_name: cpcd_0 7 | 8 | # Bus type selection 9 | # Mandatory 10 | # Allowed values : UART or SPI 11 | bus_type: UART 12 | 13 | # SPI device file 14 | # Mandatory if spi chosen, ignored if uart chosen 15 | spi_device_file: /dev/spidev0.0 16 | 17 | # SPI RX IRQ gpio chip 18 | # Ignored when using the gpio sysfs interface 19 | spi_rx_irq_gpio_chip: gpiochip0 20 | 21 | # SPI RX IRQ gpio 22 | # RX interrupt gpio selection 23 | spi_rx_irq_gpio: 22 24 | 25 | # SPI bitrate. 26 | # Ignored if uart chosen. 27 | # See doc/spi_bitrate.md for a complete explanation 28 | spi_device_bitrate: 1000000 29 | 30 | # UART device file 31 | # Mandatory if uart chosen, ignored if spi chosen 32 | uart_device_file: {{ .device }} 33 | 34 | # UART baud rate. 35 | # Optional if uart chosen, ignored if spi chosen. Defaults to 115200 36 | # Allowed values : standard UART baud rates listed in 'termios.h' 37 | uart_device_baud: {{ .baudrate }} 38 | 39 | # UART flow control. 40 | # Optional if uart chosen, ignored if spi chosen. Defaults to 'true' 41 | # Allowed values are 'true' or 'false' 42 | uart_hardflow: {{ .flow_control }} 43 | 44 | # BOOTLOADER Recovery Pins Enabled 45 | # Set to true to enter bootloader via wake and reset pins 46 | # If true, bootloader_wake_gpio and bootloader_reset_gpio must be configured 47 | bootloader_recovery_pins_enabled: false 48 | 49 | # BOOTLOADER WAKE gpio chip 50 | # Ignored when using the gpio sysfs interface 51 | bootloader_wake_gpio_chip: gpiochip0 52 | 53 | # BOOTLOADER WAKE gpio 54 | # Wakeup gpio used by the bootloader 55 | # Ensure bootloader_recovery_pins_enabled=true to use this pin 56 | bootloader_wake_gpio: 24 57 | 58 | # BOOTLOADER RESET gpio chip 59 | # Ignored when using the gpio sysfs interface 60 | bootloader_reset_gpio_chip: gpiochip0 61 | 62 | # BOOTLOADER RESET gpio 63 | # Reset pin 64 | # Ensure bootloader_recovery_pins_enabled=true to use this pin 65 | bootloader_reset_gpio: 23 66 | 67 | # Prints tracing information to stdout 68 | # Optional, defaults to 'false' 69 | # Allowed values are 'true' or 'false' 70 | stdout_trace: {{ .cpcd_trace }} 71 | 72 | # Prints tracing information to a file located under traces_folder 73 | # Optional, defaults to 'false' 74 | # Allowed values are 'true' or 'false' 75 | trace_to_file: false 76 | 77 | # Traces folder 78 | # Optional, defaults to '/dev/shm/cpcd-traces' 79 | # Folder mounted on a tmpfs is preferred 80 | traces_folder: /dev/shm/cpcd-traces 81 | 82 | # Enable frame trace 83 | # Optional, defaults to 'false' 84 | # Allowed values are 'true' or 'false' 85 | enable_frame_trace: false 86 | 87 | # Number of open file descriptors. 88 | # Optional, defaults to 2000 89 | # If the error 'Too many open files' occurs, this is the value to increase. 90 | rlimit_nofile: 2000 91 | 92 | # Disable the encryption over CPC endpoints 93 | # Optional, defaults false 94 | disable_encryption: {{ .disable_encryption }} 95 | 96 | # Binding key file 97 | # Mandatory when security is used 98 | # Must have 32 alphanumeric characters as the first line, representing a 128 bit binding key 99 | # If ECDH encryption is used, this file will be created during the binding process 100 | binding_key_file: /etc/binding-key.key 101 | -------------------------------------------------------------------------------- /rootfs/etc/s6-overlay/s6-rc.d/otbr-agent/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/with-contenv bash 2 | # ============================================================================== 3 | # OpenThread BorderRouter start script 4 | # ============================================================================== 5 | source /etc/bashlog/log.sh; 6 | 7 | . /etc/s6-overlay/scripts/otbr-agent-common 8 | 9 | declare backbone_if 10 | declare device 11 | declare baudrate 12 | declare flow_control 13 | declare otbr_log_level 14 | declare otbr_log_level_int 15 | declare otbr_rest_listen 16 | declare otbr_rest_listen_port 17 | 18 | declare thread_if 19 | 20 | thread_if="wpan0" 21 | 22 | backbone_if=$BACKBONE_IF 23 | 24 | otbr_log_level=$OTBR_LOG_LEVEL 25 | case "${otbr_log_level}" in 26 | debug) 27 | otbr_log_level_int="7" 28 | ;; 29 | info) 30 | otbr_log_level_int="6" 31 | ;; 32 | notice) 33 | otbr_log_level_int="5" 34 | ;; 35 | warning) 36 | otbr_log_level_int="4" 37 | ;; 38 | error) 39 | otbr_log_level_int="3" 40 | ;; 41 | critical) 42 | otbr_log_level_int="2" 43 | ;; 44 | alert) 45 | otbr_log_level_int="1" 46 | ;; 47 | emergency) 48 | otbr_log_level_int="0" 49 | ;; 50 | *) 51 | log 'info' "Unknown otbr_log_level: ${otbr_log_level}" 52 | otbr_log_level_int="6" 53 | ;; 54 | esac 55 | 56 | if [ -z ${backbone_if} ]; then 57 | log 'info' "No primary network interface found! Using static eth0." 58 | backbone_if="eth0" 59 | fi 60 | 61 | mkdir -p /data/thread && ln -sft /var/lib /data/thread || echo "Could not create directory /var/lib/thread to store Thread data." #TODO sys exit 62 | 63 | if [ $OTB_FIREWALL -eq 1 ]; then 64 | log 'info' "Setup OTBR firewall..." 65 | ipset create -exist otbr-ingress-deny-src hash:net family inet6 66 | ipset create -exist otbr-ingress-deny-src-swap hash:net family inet6 67 | ipset create -exist otbr-ingress-allow-dst hash:net family inet6 68 | ipset create -exist otbr-ingress-allow-dst-swap hash:net family inet6 69 | 70 | ip6tables -N $otbr_forward_ingress_chain 71 | ip6tables -I FORWARD 1 -o $thread_if -j $otbr_forward_ingress_chain 72 | 73 | ip6tables -A $otbr_forward_ingress_chain -m pkttype --pkt-type unicast -i ${thread_if} -j DROP 74 | ip6tables -A $otbr_forward_ingress_chain -m set --match-set otbr-ingress-deny-src src -j DROP 75 | ip6tables -A $otbr_forward_ingress_chain -m set --match-set otbr-ingress-allow-dst dst -j ACCEPT 76 | ip6tables -A $otbr_forward_ingress_chain -m pkttype --pkt-type unicast -j DROP 77 | ip6tables -A $otbr_forward_ingress_chain -j ACCEPT 78 | 79 | ip6tables -N $otbr_forward_egress_chain 80 | ip6tables -I FORWARD 2 -i $thread_if -j $otbr_forward_egress_chain 81 | ip6tables -A $otbr_forward_egress_chain -j ACCEPT 82 | else 83 | # Make sure ip6tables (as used by Docker) allow IP forwarding 84 | ip6tables -P FORWARD ACCEPT 85 | # HAOS 9.3 and earlier (for 9.4 accept is the default so this won't do anything) 86 | ip6tables-legacy -P FORWARD ACCEPT 87 | fi 88 | 89 | otbr_rest_listen="::" 90 | otbr_rest_listen_port="${OTBR_REST_LISTEN_PORT}" 91 | 92 | # If user port is not set, listen on local interface only 93 | if [ -z "${otbr_rest_listen_port}" ]; then 94 | otbr_rest_listen="::" 95 | otbr_rest_listen_port="8081" 96 | elif [ "${otbr_rest_listen_port}" != "8081" ]; then 97 | log 'warning' "Custom OpenThread REST API port is not supported. Using 8081." 98 | otbr_rest_listen_port="8081" 99 | fi 100 | 101 | # Store REST API listen information for check script 102 | echo "${otbr_rest_listen}" > /tmp/otbr-agent-rest-api 103 | echo "${otbr_rest_listen_port}" >> /tmp/otbr-agent-rest-api 104 | 105 | log 'info' "Starting otbr-agent..." 106 | exec s6-notifyoncheck -d -s 300 -w 300 -n 0 \ 107 | "/usr/sbin/otbr-agent" -I ${thread_if} -B "${backbone_if}" \ 108 | --rest-listen-address "${otbr_rest_listen}" \ 109 | -d${otbr_log_level_int} -v \ 110 | "spinel+cpc://cpcd_0?iid=2&iid-list=0" 111 | -------------------------------------------------------------------------------- /rootfs/etc/bashlog/log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -uo pipefail; 4 | 5 | function _log_exception() { 6 | ( 7 | BASHLOG_FILE=0; 8 | BASHLOG_JSON=0; 9 | BASHLOG_SYSLOG=0; 10 | 11 | log 'error' "Logging Exception: ${@}"; 12 | ); 13 | } 14 | 15 | function log() { 16 | local date_format="${BASHLOG_DATE_FORMAT:-+%F %T}"; 17 | local date="$(date "${date_format}")"; 18 | local date_s="$(date "+%s")"; 19 | 20 | local file="${BASHLOG_FILE:-0}"; 21 | local file_path="${BASHLOG_FILE_PATH:-/tmp/$(basename "${0}").log}"; 22 | 23 | local json="${BASHLOG_JSON:-0}"; 24 | local json_path="${BASHLOG_JSON_PATH:-/tmp/$(basename "${0}").log.json}"; 25 | 26 | local syslog="${BASHLOG_SYSLOG:-0}"; 27 | local tag="${BASHLOG_SYSLOG_TAG:-$(basename "${0}")}"; 28 | local facility="${BASHLOG_SYSLOG_FACILITY:-local0}"; 29 | local pid="${$}"; 30 | 31 | local level="${1}"; 32 | local upper="$(echo "${level}" | awk '{print toupper($0)}')"; 33 | local debug_level="${DEBUG:-0}"; 34 | 35 | shift 1; 36 | 37 | local line="${@}"; 38 | 39 | # RFC 5424 40 | # 41 | # Numerical Severity 42 | # Code 43 | # 44 | # 0 Emergency: system is unusable 45 | # 1 Alert: action must be taken immediately 46 | # 2 Critical: critical conditions 47 | # 3 Error: error conditions 48 | # 4 Warning: warning conditions 49 | # 5 Notice: normal but significant condition 50 | # 6 Informational: informational messages 51 | # 7 Debug: debug-level messages 52 | 53 | local -A severities; 54 | severities['DEBUG']=7; 55 | severities['INFO']=6; 56 | severities['NOTICE']=5; # Unused 57 | severities['WARN']=4; 58 | severities['ERROR']=3; 59 | severities['CRIT']=2; # Unused 60 | severities['ALERT']=1; # Unused 61 | severities['EMERG']=0; # Unused 62 | 63 | local severity="${severities[${upper}]:-3}" 64 | 65 | if [ "${debug_level}" -gt 0 ] || [ "${severity}" -lt 7 ]; then 66 | 67 | if [ "${syslog}" -eq 1 ]; then 68 | local syslog_line="${upper}: ${line}"; 69 | 70 | logger \ 71 | --id="${pid}" \ 72 | -t "${tag}" \ 73 | -p "${facility}.${severity}" \ 74 | "${syslog_line}" \ 75 | || _log_exception "logger --id=\"${pid}\" -t \"${tag}\" -p \"${facility}.${severity}\" \"${syslog_line}\""; 76 | fi; 77 | 78 | if [ "${file}" -eq 1 ]; then 79 | local file_line="${date} [${upper}] ${line}"; 80 | echo -e "${file_line}" >> "${file_path}" \ 81 | || _log_exception "echo -e \"${file_line}\" >> \"${file_path}\""; 82 | fi; 83 | 84 | if [ "${json}" -eq 1 ]; then 85 | local json_line="$(printf '{"timestamp":"%s","level":"%s","message":"%s"}' "${date_s}" "${level}" "${line}")"; 86 | echo -e "${json_line}" >> "${json_path}" \ 87 | || _log_exception "echo -e \"${json_line}\" >> \"${json_path}\""; 88 | fi; 89 | 90 | fi; 91 | 92 | local -A colours; 93 | colours['DEBUG']='\033[34m' # Blue 94 | colours['INFO']='\033[32m' # Green 95 | colours['NOTICE']='' # Unused 96 | colours['WARN']='\033[33m' # Yellow 97 | colours['ERROR']='\033[31m' # Red 98 | colours['CRIT']='' # Unused 99 | colours['ALERT']='' # Unused 100 | colours['EMERG']='' # Unused 101 | colours['DEFAULT']='\033[0m' # Default 102 | 103 | local norm="${colours['DEFAULT']}"; 104 | local colour="${colours[${upper}]:-\033[31m}"; 105 | 106 | local std_line="${colour}${date} [${upper}] ${line}${norm}"; 107 | 108 | # Standard Output (Pretty) 109 | case "${level}" in 110 | 'info'|'warn') 111 | echo -e "${std_line}"; 112 | ;; 113 | 'debug') 114 | if [ "${debug_level}" -gt 0 ]; then 115 | echo -e "${std_line}"; 116 | fi; 117 | ;; 118 | 'error') 119 | echo -e "${std_line}" >&2; 120 | if [ "${debug_level}" -gt 0 ]; then 121 | echo -e "Here's a shell to debug with. 'exit 0' to continue. Other exit codes will abort - parent shell will terminate."; 122 | bash || exit "${?}"; 123 | fi; 124 | ;; 125 | *) 126 | log 'error' "Undefined log level trying to log: ${@}"; 127 | ;; 128 | esac 129 | } 130 | 131 | declare prev_cmd="null"; 132 | declare this_cmd="null"; 133 | trap 'prev_cmd=$this_cmd; this_cmd=$BASH_COMMAND' DEBUG \ 134 | && log debug 'DEBUG trap set' \ 135 | || log error 'DEBUG trap failed to set'; 136 | 137 | # This is an option if you want to log every single command executed, 138 | # but it will significantly impact script performance and unit tests will fail 139 | 140 | #trap 'prev_cmd=$this_cmd; this_cmd=$BASH_COMMAND; log debug $this_cmd' DEBUG \ 141 | # && log debug 'DEBUG trap set' \ 142 | # || log error 'DEBUG trap failed to set'; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Silabs multiprotocol for HA docker installation 2 | 3 | This container is a **standalone** version of the [Silicon Labs multiprotocol addon for HAOS](https://skyconnect.home-assistant.io/procedures/enable-multiprotocol/). without the HAOS stuff. 4 | 5 | ![](https://img.shields.io/github/license/b2un0/silabs-multipan-docker.svg) 6 | ![](https://img.shields.io/github/stars/b2un0/silabs-multipan-docker) 7 | ![](https://img.shields.io/docker/v/b2un0/silabs-multipan-docker) 8 | ![](https://img.shields.io/docker/pulls/b2un0/silabs-multipan-docker.svg) 9 | ![](https://img.shields.io/docker/image-size/b2un0/silabs-multipan-docker.svg) 10 | 11 | > [!WARNING] 12 | > This project is deprecated due to discontinued multiprotocol support for Home Assistant SkyConnect (ZBT-1). 13 | > 14 | > See https://www.home-assistant.io/connectzbt1 15 | 16 | # ❗ Attention ❗ 17 | 18 | I do not provide any support for the software running in this container. 19 | 20 | I have only provided a `standalone` version of the Silabs multiprotocol container which can run **without** `HAOS` 21 | 22 | ## Credits 23 | 24 | Based on the work by [@nervousapps](https://github.com/nervousapps/haDOCKERaddons/tree/master/silabs-multiprotocol/dockerCustom) 25 | and [m33ts4k0z](https://github.com/m33ts4k0z/silabs-multipan-docker) 26 | 27 | ## Versions 28 | 29 | see [VERSIONS.md](VERSIONS.md) 30 | 31 | ## Changelog 32 | 33 | see [CHANGELOG.md](CHANGELOG.md) 34 | 35 | ## Docs 36 | 37 | see [DOCS.md](DOCS.md) 38 | 39 | ## Base 40 | 41 | see [BASE.md](BASE.md) 42 | 43 | ## ❗ requirements ❗ read carefully ❗ 44 | 45 | 1. the container must run in `host` network mode 46 | 2. working `IPv6` in your LAN 47 | 3. the container must run with `--privileged` flag 48 | 4. the name of your network interface (try `ifconfig` or `ip a`) to set `BACKBONE_IF` correctly 49 | 5. the path of your Device like `/dev/tty???` (`/dev/serial/by-id/` will not work out of the box) 50 | 6. **Zigbee channel and Thread channel must be configured to the same** 51 | 7. Port `8081` is not in use because the OTBR API use is (can't be changed) 52 | 53 | ## environment variables 54 | 55 | take a look at the [Dockerfile](Dockerfile) file for more information 56 | 57 | ## getting started 58 | 59 | ⚠️ change `DEVICE` and `BACKBONE_IF` to your environment ⚠️ 60 | 61 | ### as docker run 62 | 63 | ```bash 64 | docker run --name multipan \ 65 | --detach \ 66 | --privileged \ 67 | --network host \ 68 | --restart unless-stopped \ 69 | --volume ~/multipan/:/data \ 70 | --env DEVICE="/dev/ttyUSB0" \ 71 | --env BACKBONE_IF="eth0" \ 72 | b2un0/silabs-multipan-docker:latest 73 | ``` 74 | 75 | ### as docker compose 76 | 77 | 1. download the [docker-compose.yml](docker-compose.yml) or copy the service to your existing one 78 | 2. change the config in `environment` if necessary 79 | 3. run `docker compose up -d` 80 | 81 | ## Setup OpenThread Border Router 82 | 83 | open in your browser `http://HOST:8086` and configure your OTBR 84 | 85 | ## Home Assistant 86 | 87 | ### OTBR 88 | 89 | add a new Device Integration `Open Thread Border Router` and use as Host `http://HOST:8081` as Endpoint. 90 | 91 | ### ZHA 92 | 93 | 1. Add the Zigbee Home Automation (`ZHA`) integration 94 | 2. Choose `EZSP` as Radio type 95 | 3. As serial path, enter `tcp://host_ip:20108` or `socket://host_ip:20108` 96 | 4. Port speed `460800` 97 | 5. flow control `hardware` 98 | 99 | ## Setup Zigbee2MQTT 100 | 101 | To use this with `Zigbee2MQTT` change the `configuration.yaml` file of Zigbee2MQTT to this configuration: 102 | 103 | ```yaml 104 | serial: 105 | port: tcp://host_ip:20108 106 | adapter: ezsp 107 | baudrate: 460800 108 | ``` 109 | 110 | Restart `Zigbee2MQTT`. 111 | It might take a couple of tries for `Zigbee2MQTT` to connect the first time, but it will work without issues afterward. 112 | 113 | ## Matter 114 | 115 | you also need the [python-matter-server](https://github.com/home-assistant-libs/python-matter-server) if you want to use Matter enabled devices with Home Assistant. 116 | 117 | ### Firmware Update 118 | 119 | 1. download the newer firmware from https://github.com/NabuCasa/silabs-firmware/tree/main/RCPMultiPAN/beta 120 | 2. place them into your local directory `~/multipan/firmware/` (if your `/data` Volume mounted to `~/multipan/`) 121 | 3. change the environment variable `FIRMWARE` to the new Filename (without path) 122 | 4. change the environment variable `AUTOFLASH_FIRMWARE` to `1` 123 | 5. redeploy your container 124 | 125 | ## Docker Base Images 126 | 127 | | arch | url | 128 | |---------|---------------------------------------------------------------------------| 129 | | aarch64 | https://hub.docker.com/r/homeassistant/aarch64-addon-silabs-multiprotocol | 130 | | amd64 | https://hub.docker.com/r/homeassistant/amd64-addon-silabs-multiprotocol | 131 | | armv7 | https://hub.docker.com/r/homeassistant/arm-addon-silabs-multiprotocol | 132 | | i386 | not exists (not supported by HA) | 133 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2017 Pascal Vizeli 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. --------------------------------------------------------------------------------