Connecting Velux Active KIX 300

Tags: #<Tag:0x00007f745359b6d0> #<Tag:0x00007f745359b608> #<Tag:0x00007f745359b540>

If you can’t get it working with the OpenHAB binding, there are a few projects that let you connect HomeKit “official devices” to other protocols.

mqtt2homekit will run an npm package that will basically translate the homekit device over to mqtt.

If you prefer python, check out homekit_python - you’ll want to check out the HomeKit Controller section of that project.

I believe that mqtt2homekit would be easier to set up (for me at least) but you may be a python pro!

Oh, both projects look promising. Thanks for the links!

I assume mqtt2homekit can be added to OH using mqtt. How to integrate homekit_python correctly? Looks like it’s mostly shellouts so I assume exec binding?

Currently waiting for the KIX300 to arrive *excited* :slight_smile:

Correct. This one would be easier for me to set up due to my understanding of NPM and MQTT.

If you pick this one you’ll probably want to search the forums to see how others are running python scripts integrated with openhab, since that’s basically what it appears to be.

Some updates here. I got the device and overall I like it. The Velux App does not have a lot of features but controlling my shutters works fast and reliable.

The automatic home control feature is very basic and I don’t like that some AI is opening or closing my shutters at random times. I don’t have it enabled.

Since the device is called Velux with Netatmo. I expected some integration with Netatmo service and maybe even using the openHab Netatmo binding. Unfortunately there is no customer visible Neatmo integration. The API is similar but uses different hostnames and only a few methods are implemented. So pretty useless.

Regarding openHab integration: I did not try homekit integration yet. But I reverse engineered most of the Android App. The API has a lot of overlap with Netatmo API but only a few methods are implemented. OpenHab uses https://github.com/cbornet/netatmo-swagger-api for calling the Netatmo API and it looks like the API endpoint is not easily changeable. So I could not try the integration. In addition there is a second undocumented Netamo API FHEM is using: https://github.com/mericon/fhem/blob/master/FHEM/38_netatmo.pm (/syncapi/v1/). I was able to extract client_id and client_secret from the Android API and reverse engineer most API operations so I can control my shutters via some bash script.

I don’t think I know enough about OpenHab to develop my own binding. I’m also not sure if it would be ok to share the extracted oAuth details from the Android APK. Neither I think it would be a good idea to extend the current Netatmo binding with Velux specifics.

Regarding functionality I can extract following data:

  • position of all shutters (percentage)
  • read air quality, co2, humidity, lux, temperature, pressure
  • read if home is locked and lock it.
  • all kind of metadata: Battery, signal strength, last seen, firmware version …
  • control shutters

I very much appreciate your efforts. I would love to see a binding for this as the limit to 5 (groups of) devices makes the old gateway a no go for me. I have been controlling my Velux windows and shutters with remote controls connected to a Raspberry Pi but that has its own limitations.
Thanks for taking starting this. Hopefully somebody can support this effort (Unfortunately not my area of expertise).

There is the existing velux binding for KLF200 which (I think) supports more than 5 devices if you run Firmware 2.0: New Binding for Velux

Maybe that’s supporting your use-case better/earlier

Some update here. I have a early version of a swagger definition for the velux API: https://pastebin.com/raw/ryyNQx9V ( use the link with https://editor.swagger.io/ to read it/generate a client).

example usage:

SwaggerClient.configure do |config| 
  config.access_token = jsontoken["access_token"] 
end 
 
api_instance = SwaggerClient::DefaultApi.new 

result = api_instance.homesdata 
 
home = result.body.homes.first 
home_id = home.id 
 
rooms = {} 
room_for_module = {} 
home.rooms.each do |r| 
  rooms[r.id] = r 
  r.modules.each do |m| 
    room_for_module[m] = r.id 
  end 
end 
 
modules = {} 
home.modules.each do |m| 
  modules[m.id] = m 
end 
 
result = api_instance.homestatus(:body => { 
  'home_id' => home_id 
}) 
 
module_status = {} 
result.body.home.modules.each do |m| 
  module_status[m.id] = m 
end 
 
SHUTTER = "NXO" 
SENSOR = "NXS" 
DEPATURE = "NXD" 
BRIDGE = "NXG" 
 
AIR_QUALITY = { 
  0 => "Healthy", 
  1 => "Fine", 
  2 => "Fair", 
  3 => "Poor", 
  4 => "Unhealthy" 
} 
 
result.body.home.rooms.each do |r| 
  if r.air_quality 
    puts "#{rooms[r.id].name} (air quality: #{AIR_QUALITY[r.air_quality]} / CO2: #{r.co2} / temperature: #{r.temperature/10.0} / humidity: #{r.humidity} / lux: #{r.lux})" 
  else 
    puts rooms[r.id].name 
  end 
  rooms[r.id].modules.map {|x| module_status[x] }.each do |m| 
    if m.type == SHUTTER 
      puts "  - [#{"#" * (10-(m.current_position/10.0))}#{" " * (m.current_position.to_i/10.0)}] #{modules[m.id].name}" 
    else 
      puts "  - #{modules[m.id].name}: battery: #{m.battery_percent}% rf stength: #{m.rf_strength}" 
    end 
  end 
end 

produces something like:

Bedroom (air quality: Fine / CO2: 393 / temperature: 20.3 / humidity: 55 / lux: 0) 
  - Sensor switch 1: battery: 95% rf stength: 60 
  - [          ] Bedroom1 
Dining room 
  - [          ] Dining 1 
Kitchen 
  - [          ] Kitcchen 
Corridor 
  - [          ] Corridor 1 
  - [          ] Corridor 2 
Living room 
  - [          ] Living room 1 
  - [          ] Liing room 2 
Office 
  - [          ] Office 1 
  - [##########] Office 2  

I’m currently working on integration into openHab using the exec binding and my go binary.

Hi, I’m very interested to hear more about this. Is there already an update for the implementation?
And how can I determine/extract the client-id and client-secret from the Adnroid Api? I didn’t quite understand that.
Thanks

Martin

1 Like

I was reading through the de-obfuscated code using jadx but I think it’s easier to just sniff the communication using mitmproxy. Since the client_id and client_secret are sent in plain-text it’s possible to extract. Unfortunately Velux has certificate pinning enabled which means sniffing the traffic requires patching the APP.

Steps required for patching the Android APK:

  • Get the APK (either download it form some shady websites or use some apk share/backup app)
  • Get apktool
  • unpack with apktool d com.velux.active_1.5.0.7-all-arm64-v8a.apk
  • Remove certificate pinning from com.velux.active_1.5.0.7-all-arm64-v8a/res/xml/network_security_config.xml
    • remove pin-set
    • add instead <trust-anchors><certificates src="system" /><certificates src="user" /></trust-anchors>
  • Build the apk again with apktool b -o /tmp/test.apk com.velux.active_1.5.0.7-all-arm64-v8a
  • Sign the apk with a developer key: apksigner sign -ks ~/android.jks --in /tmp/test.apk --out /tmp/com.velux.active_1.5.0.7-all-arm64-v8a_signed.apk
  • install the APK adb install /tmp/com.velux.active_1.5.0.7-all-arm64-v8a_signed.apk

Now the network sniffing part:

  • start mitmproxy on your laptop (for example on ip 192.168.1.10)
  • Install the mitmproxy certificate in android as user certificate (you can find it in ~/.mitmproxy)
  • set android proxy ip to your laptop: adb shell settings put global http_proxy 192.168.1.10:8080

You should see network traffic coming through the mitmproxy and you can see the oauth token exchange when you open the velux app and all other API calls.

In case you have blinds and windows I would be interested how the API looks like. I would be very happy if you have any mitmproxy traces for me! (double check if they contain any private data before sending! I will not publish any traces but you can’t trust strangers).

Once you’re done delete the proxy settings, restart your phone double check there are no new calls in mitmproxy and stop the proxy. Uninstall the patched velux app and reinstall from the play store.

You can delete proxy settings using:

$ adb shell settings delete global http_proxy 192.168.1.10:8080 
$ adb shell settings delete global global_http_proxy_host 
$ adb shell settings delete global global_http_proxy_port 

I can understand this all looks incredible complicated but I was surprised to be easier than expected. Nevertheless I hope there will be a easier way eventually.

1 Like

@nougad: I just got my Velux window rollershutter installed and have a KIX 300 now. You mentioned earlier you want to have something done for openhab using the exec binding. Do you have something done already?

Thanks so far for the effort you spend on this!

Sorry for the month of silence. I was finally able to put everything together and publish a early state on github: https://github.com/nougad/velux-cli

It contains the API documentation and a go client. I documented the openHab integration using exec binding here: https://github.com/nougad/velux-cli/blob/master/openhab.md

I still haven’t published the ClientID and ClientSecret from the Velux App. You still require extracting this yourself. I know, that’s not a awesome experience but I don’t want to publish private keys.

For the same reason I’m not working on a openHab binding at the moment.

Contributions welcome.

Thanks will check it out as soon as I find time. Regarding the keys … the question is how private is private if it is part of every application installed on customers devices :slight_smile:

yes, that’s correct the keys are kind of public by including it into a obfuscated Android app. It’s not on me to define “private” :slight_smile: Feel free to publish the keys but I will not take the risk

@nougad
How you solve the issue with the Gateway pairing at the first login.
How you get the sign_key_id to open a window?

Hey @tombox. I don’t fully understand what you mean with sign_key_id and opening a window. My code works by getting the oAuth2 keys and directly talking with the Velux backend.

Ok this means you never open a Velux window with your code.

@tombox Ah, now I understand. I only own Velux roller shutter which don’t require a sign_key_id. Right now the code does not support windows since I can’t try it. It would require someone with a window to captures the network traffic and either create a pull request to the swagger definition or to provide me the wire dump of the network traffic.

Unfortunately there is only encrypted communication between the gateway and the phone nothing capturable via https

@tombox that’s correct. I described above how you can remove the certificate pinning and route the network traffic through a mitm proxy. It’s a bit tricky to setup but I think the only way to get the necessary data.

This is not the issue because the the is no traffic via https is looks like a direct connection between gateway and phone. The Gateway sends a broadcast and the app on the receive the package and generate a hash. This hash will be send to the gateway with a hashed target position. But the decompiled hash algorithm are hard to reproduce.