This document is archival/debug documentation for manually extracting roof-window signing keys.
Normal users should use the Home Assistant gateway pairing flow instead. The pairing flow retrieves signing keys directly from the VELUX gateway and does not require Android patching, mitmproxy, smali editing, or manual Home Assistant storage edits.
Use this document only if:
- Gateway pairing cannot be used on your network.
- You are debugging the signing implementation.
- You understand the risks of installing a patched Android APK and intercepting local app traffic.
Do not edit Home Assistant .storage/core.config_entries directly. If you already have keys, enter them through the integration setup flow or options flow.
The repo includes a small end-to-end helper that runs the whole pairing flow outside the Home Assistant UI:
python3 dev/retrieve-signing-key.py --username YOU@EXAMPLE.COM --host GATEWAY_IP_OR_HOSTNAMEIt logs in to VELUX/Netatmo, triggers cloud retrieve_key mode on the gateway, prompts you to press the physical gateway button once the LED flashes, then reads the signing key from the gateway's local Netcom listener — the same sequence the config flow runs.
For multi-gateway accounts, pass --gateway GATEWAY_MODULE_ID; the password is prompted if --password is omitted. It needs the same runtime deps as the integration (pyatmo, aiohttp, cryptography), though --help works without them.
- An Android phone connected to the same Wi-Fi as the VELUX gateway.
- A computer with
adb,apktool,apksigner, and optionallymitmproxy. - Your VELUX ACTIVE gateway powered on and accessible.
iOS is not practical for this method because the app uses certificate pinning that prevents normal interception.
Install mitmproxy if you want to inspect API traffic:
# macOS
brew install mitmproxy
# Linux
pip install mitmproxyInstall Android platform tools:
# macOS
brew install android-platform-tools
# Linux
sudo apt install android-tools-adbInstall apktool:
# macOS
brew install apktool
# Linux
sudo apt install apktoolapksigner is included with Android SDK build tools. Install Android SDK build tools and add them to your PATH if apksigner is missing.
Verify the tools:
mitmproxy --version
adb version
apktool --version
apksigner --version- On the Android phone, open Settings -> About Phone.
- Tap Build number 7 times to enable Developer Options.
- Open Settings -> Developer Options.
- Enable USB Debugging.
- Connect the phone to the computer by USB and allow the debug prompt.
Verify the phone is detected:
adb devicesInstall the regular VELUX ACTIVE app on the phone, then pull its APK files:
mkdir -p ~/velux-apks
adb shell pm path com.velux.active | tr -d '\r' | while IFS= read -r line; do
apk="${line#package:}"
adb pull "$apk" "$HOME/velux-apks/$(basename "$apk")"
doneDecompile the base APK:
apktool d ~/velux-apks/base.apk -o ~/velux_patchedPatch the network security config to trust user certificates:
cat > ~/velux_patched/res/xml/network_security_config.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system"/>
<certificates src="user"/>
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">fw.netatmo.net</domain>
<trustkit-config disableDefaultReportUri="true" enforcePinning="false">
<report-uri>https://cert-pinning.netatmo.com/</report-uri>
</trustkit-config>
</domain-config>
</network-security-config>
EOFFind the certificate pinning failure handler:
grep -rn "Certificate pinning failure" ~/velux_patched/smali* -lOpen the matching smali file and find a method like:
.method public final a(Ljava/lang/String;Ljava/util/List;)VReplace the method body with return-void, for example:
.method public final a(Ljava/lang/String;Ljava/util/List;)V
.locals 1
return-void
.end methodIf you do not want to use mitmproxy, patch the signing mapper to log both values to logcat.
Search for the signing mapper:
grep -rn "HashMapperKey" ~/velux_patched/smali* | headIn one tested APK version, the mapper was located at:
~/velux_patched/smali/android/br1.smali
The exact file and registers can change between app versions. Use nearby move-result-object registers when adding log statements.
Add a log after the sign key ID is converted to a string:
const-string v3, "velux-key-id"
invoke-static {v3, v2}, Landroid/util/Log;->w(Ljava/lang/String;Ljava/lang/String;)IAdd a log after the hash sign key is converted to a string:
const-string v11, "velux-debug"
invoke-static {v11, v10}, Landroid/util/Log;->w(Ljava/lang/String;Ljava/lang/String;)IRepeat both additions lower in the same mapper file if the APK has two signing paths. Verify the tags exist:
grep -rn 'velux-key-id\|velux-debug' ~/velux_patched/smali*Generate a signing key:
keytool -genkey -v -keystore ~/velux-key.keystore -alias velux \
-keyalg RSA -keysize 2048 -validity 10000 \
-storepass password123 -keypass password123 \
-dname "CN=Velux, O=Test, C=GB"Rebuild and sign the APK:
rm -rf ~/velux_patched/build
apktool b ~/velux_patched -o ~/velux-patched.apk
mkdir -p ~/velux-signed
apksigner sign \
--ks ~/velux-key.keystore \
--ks-pass pass:password123 \
--key-pass pass:password123 \
--out ~/velux-signed/base.apk \
~/velux-patched.apkIf apktool b fails with drawable/resource errors, check for empty drawable entries in res/values/drawables.xml and replace them with transparent values such as #00000000. Some APK versions may also need android:drawable="@null" items replaced with transparent shape items.
Sign split APKs if the app uses them:
for apk in ~/velux-apks/split_config*.apk; do
[ -e "$apk" ] || continue
apksigner sign \
--ks ~/velux-key.keystore \
--ks-pass pass:password123 \
--key-pass pass:password123 \
--out "$HOME/velux-signed/$(basename "$apk")" \
"$apk"
doneInstall the patched app:
adb uninstall com.velux.active
install_apks=(~/velux-signed/base.apk)
for apk in ~/velux-signed/split_config*.apk; do
[ -e "$apk" ] || continue
install_apks+=("$apk")
done
adb install-multiple "${install_apks[@]}"Some Android variants, such as MIUI, may require disabling app verification in Developer Options.
If you patched log statements into the APK, start logcat:
adb logcat -s velux-key-id:W velux-debug:WOpen the patched VELUX app, log in, pair with the gateway, and move a roof window. You should see output like:
W velux-key-id: sign_key_id
W velux-debug: hash_sign_key
Use these values in the integration setup/options flow:
- Hash Sign Key: the
velux-debugvalue. - Sign Key ID: the
velux-key-idvalue.
Find your computer's local IP address:
# macOS
ipconfig getifaddr en0
# Linux
hostname -I | awk '{print $1}'Start mitmproxy:
mitmproxy --listen-port 8080 \
--ignore-hosts "app-ws\.velux-active\.com|googleapis\.com|google\.com|gstatic\.com|crashlytics\.com|firebase\.com|flurry\.com"On the Android phone:
- Open Wi-Fi network settings.
- Set proxy to Manual.
- Set host to your computer IP address.
- Set port to
8080.
Install the mitmproxy certificate:
- Open Chrome on the phone and go to
http://mitm.it. - Tap Android and download the certificate.
- Install it from Android security settings.
You can also set the proxy by adb:
adb shell settings put global http_proxy YOUR_COMPUTER_IP:8080Open the patched VELUX app, log in, pair with the gateway, and move a roof window. In mitmproxy, inspect a POST /syncapi/v1/setstate request. The JSON body contains sign_key_id.
If you also patched logcat for the hash key, combine:
- Hash Sign Key:
velux-debuglogcat value. - Sign Key ID:
sign_key_idfrom the setstate request body.
Remove the proxy from the phone:
adb shell settings put global http_proxy :0Set Wi-Fi proxy back to None in Android network settings.
You can uninstall the patched app and reinstall the regular VELUX app from the Play Store.