Skip to content

Latest commit

 

History

History
149 lines (118 loc) · 11.6 KB

reverse_engineering.md

File metadata and controls

149 lines (118 loc) · 11.6 KB

Reverse-Engineering Process

This document provides an overview of the steps I took to gather the necessary information and make the package functional:

  1. I downloaded and installed the Ambientika Android App
  2. I registered the device using the official app to get everything set up.
  3. Now I installed the PCAPdroid - network monitor to be able to see the requested URLs and Ports.
  4. After a bit of configuration, I was able to track the network traffic of the App and see the servers and ports that it connected to:
    PCAPdroid Screenshot
  5. Next, I searched for the server documentation and discovered it was available on Swagger UI
  6. After locating the documentation, the process involved:
    • reading the documentation
    • testing various REST calls using curl
    • iterating until successful
    • implementing the functional REST calls in Home Assistant configuration files
    • adjusting the configuration to ensure compatibility with Home Assistant

In addition to the aforementioned approach, I intercepted the network traffic using an old tablet running Android 4. Originally the plan was to do this on my actual phone or a virtual/simulated device. But according to the description of the PCAPdroid mitm-Addon such a man-in-the-middle attack does not work under the following conditions:

  • Android > 7
  • app target SDK > 23

So my ancient Android 4 Tablet was the perfect candidate to decrypt the messages and verify the REST Endpoints and payloads, as well as their frequency.

Setting Up the Home Assistant Package

To start with the new package, I first created the necessary folders and added entries to the configuration.yaml following the instructions in the Installation and Setup section. Next, I created each YAML file one by one and filled them with the necessary code to ensure the required entities appeared.

Note: The Ambientika Token is excluded from the recorder because it contains sensitive information. Therefore, it should not be written to the history database!

Creating the REST Commands and REST Sensors

The package primarily relies on the following three Home Assistant Integrations:

  • RESTful Command (to expose REST commands as service for a script or automation)
  • RESTful Sensor (for setting up a single sensor)
  • RESTful (for multiple sensor or binary_sensor from the same REST endpoint)

The package also includes several helpers and automations to support the REST commands.



Essentially, the process involved testing and YAML work, using the Swagger UI as a reference in the following order:

1. Get the authentication token into Home Assistant (since the tokens expire after 180 days)

curl -X POST https://app.ambientika.eu:4521/users/authenticate \
  -H 'Content-Type: application/json' \
  -d '{"username":"[email protected]","password":"my-secret-password"}'

This command could be easily implemented in rest_commands.yaml

  • Refer to the documentation for the correct syntax
  • The command will then be exposed as a service in Home Assistant

2. Check remaining days for monitoring and renewing the token, before it expires

curl -X GET https://app.ambientika.eu:4521/users/token-info \
  -H 'Content-Type: application/json' \
  -H 'authorization: Bearer my-super-secret-token'

The feedback value is a datetime, which needs to be converted to days. So first I needed to convert it to a timestamp, subtract the current time, and divide by 60/60/24 to convert from seconds to minutes, hours, and finally, days. According to the settings in the sensors.yaml, the token info is polled every hour (3600 seconds).

3. Automation: Refresh Token once Home Assistant is started or if the remaining days fall below a certain value

See the automation.yaml for details. It essentially retrieves the token and sets the value of the input_text.ambientika_access_token (see helpers.yaml and customize.yaml)

4. Get the Device Status as Sensors in Home Assistant

curl -X GET   https://app.ambientika.eu:4521/device/device-status?deviceSerialNumber=123456789ABC \
  -H 'Content-Type: application/json' \
  -H 'authorization: Bearer my-super-secret-token'

This request returns all relevant status information of the device. Therefore, I use the RESTful integration to return the received data as Home Assistant entities. As can be seen from the sensors.yaml, this command provides:

  • sensor:
    • Operating Mode
    • last Operating Mode
    • Fan Speed
    • Filter Status
    • Temperature (raw)
    • Humidity (raw)
    • Air Quality
  • binary_sensor:
    • Humidity Alarm
    • Night Alarm

Note: Unfortunately resource or resource_template do not support combining a fixed string with a secret, such as the device ID. Therefore, this URL is listed separately as device-status-1 in the secrets.yaml.

5. Change Mode command

curl -X POST https://app.ambientika.eu:4521/device/change-mode \
  -H 'Content-Type: application/json' \
  -H 'authorization: Bearer my-super-secret-token' \
  -d '{"deviceSerialNumber":"123456789ABC","operatingMode":"Smart","fanSpeed":1,"humidityLevel":1}'

This command is also implemented in rest_commands.yaml and exposed as a service, allowing it to be used in automations and scripts.

6. Control Entities and Automation

To control the operatingMode several Input entities where necessary. As can be seen from the helpers.yaml, there are three input entities:

  • Fan Speed (only necessary in operatingMode ManualHeatRecovery)
  • Humidity Level (only necessary in operatingMode Auto and Surveillance)
  • Mode Selection (always necessary, except in mode Off)

To push this information to the Ambientika Control Server, the Change Mode command from the previous point is used, as can be seen in the automation.yaml, including the values for Fan Speed and Humidity Level.

7. Switch for on/off control

In the end, I decided to implement a Template Switch in the switch.yaml to be able to turn the device on and off the device with any hardware button you might have integrated into your Home Assistant instance. The actions of the switch are basically a copy of the actions from Automation. This includes a homeassistant.update_entity command after a short delay to get the updated operatingMode after turning the device on or off.

Filter values

Unfortunately the numerical Values from the sensors had a lot of jitter, so I tried to find a suitable filter for these sensors. This involved a lot of trial and error, waiting for values to be generated, and comparing the different tests:
Filter comparison: Lowpass vs. Time Simple Moving Average

As can be seen in the picture above:

  • The Time Simple Moving Average-Filter (orange and dark yellow) creates a nice graph, close to the original entity with it "raw value". But it still has some jitter that needs to be cleared out.
  • The Lowpass-Filter (purple and cyan) on the other hand, make the graph smooth, but with unacceptable deviation from the original entity.

So, both were combined to create smooth values:
Filter result

Note: Don't get confused with these high values. I made the settings, filters and screenshots when the wall was freshly plastered. Therefore, the device was measuring a lot of moisture from the wall. The values reduced to a normal level after a couple of weeks.

Getting the Images for the UI

To get the images for the UI, I wanted to reuse the original images from the Android app. Of course, I could have made a couple of screenshots, cropped them, and used those as PNG files, but I followed a more sophisticated workflow:

  1. I extracted the APK using the APK Extractor and transferred it to the PC.
  2. Disassembled the APK using the Apktool: apktool d '.\Ambientika APP.apk'.
  3. I searched for image files. In this case, I found that .svg files were used to render the user interface.
  4. After examining the images, I tried to match them with the operatingMode.
Image operatingMode
Smart
Auto*
Night
AwayHome
ManualHeatRecovery**
Expulsion
MasterSlaveFlow
SlaveMasterFlow
Intake
TimeExpultion***
Surveillance*
Off

* The humidity slider is active, and the set humidity target is shown next to the house. Also, the humidity-value on the left is shown in red, if the humidityAlarm is active.
** The temperature slider is active, and the current fan level is shown next to the house.
*** According to the App-Manual (page 22/24) the TimeExpultion Mode is running for 20 minutes on max. fan speed. Afterwards it returns to the mode, stored in the lastOperatingMode attribute.