Python library and CLI to manage Prana recuperators (https://prana.org.ua/) via BLE interface. It provides access to the device API and provides functionality similar to the functionality of the official mobile application with some limitations (see limitation section below).
ATTENTION: The manufacturer doesn't provide any technical documentation describing the protocol and also officially doesn't provide an ability to interact with the devices programmatically. This library is based on reverse engineering of the closed proprietary protocol. Use it at your own risk.
Features:
- Read current prana state
- Control everything which could be managed via an official app with a few exceptions (see limitations section)
- Discover not connected devices around
- Client-server architecture (allows distributed setup)
- CLI interface available for quick tinkering
For Linux hosts:
- Make sure you have Bluez component installed. E.g. on debian based systems you can use
sudo apt-get install bluez
The easiest way is to use pip. To install the recent version with HTTP API support run:
pip install prana-rc[server-tornado]
If you prefer dockerized setup you could run it like this:
docker run --volume /run/dbus/system_bus_socket:/run/dbus/system_bus_socket -p 8881:8881 --restart=unless-stopped corvis/prana-rc:latest
By default it will run http-server
command, however you could run any cli commend by addign extra arguments to the
end. For example to run discover you could use:
docker run --rm --volume /run/dbus/system_bus_socket:/run/dbus/system_bus_socket corvis/prana-rc:latest discover
NOTE: It is highly recommended to use the fixed version instead of latest
to avoid unintended upgrades.
API is based on JSON RPC 2.0 standard. The server exposes one single endpoint for handling rpc requests, any other requests will be declined.
According to json rpc specification, the request must be a POST HTTP request with Content-Type
set
to application/json
and the body containing json of the following structure:
{
"jsonrpc": "2.0",
"method": "METHOD_NAME",
"id": 1,
"params": []
}
Where params might be omitted if the method doesn't require any arguments. Params also could be an object if you prefer keyword arguments instead of positional args. id
is a unique identifier of the request (relevant for async APIs),
it should be generated by the client and it will be returned back with the response.
It is important to include id
and jsonrpc
fields into the request otherwise.
The table below describes the exposed API methods:
Discovers available Prana devices nearby.
Important: It will discover only those devices which are not connected to any client (either mobile app, prana_rc or any other).
Method name: prana.discover
Name | Type | Required | Description |
---|---|---|---|
timeout | int | no | Time in seconds to wait for the device's announcement. Default: 4s. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "prana.discover",
"params": {}
}
Shell command
curl \
-X POST \
-H "Accept: application/json" \
http://YOUR_IP:8881/ \
-d '{ "jsonrpc": "2.0", "id": 1, "method": "prana.discover" }'
{
"result":[
{
"address":"00:A0:50:99:52:D2",
"bt_device_name":"PRNAQaqBEDROOM",
"name":"BEDROOM",
"rssi":-87
}
],
"id":1,
"jsonrpc":"2.0"
}
Method name: prana.get_state
Name | Type | Required | Description |
---|---|---|---|
address | string | yes | Mac address of the device to communicate with. Could be obtained from prana.discover query result |
timeout | int | no | Time in seconds to wait for successful command execution. Default: 5s. |
attempts | int | no | Number of connection attempts to make before the failure Default: 5. |
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "prana.get_state",
"params": {"address": "XX:XX:XX:XX:XX:XX"}
}
Shell command
curl \
-X POST \
-H "Accept: application/json" \
http://YOUR_IP:8881/ \
-d '{ "jsonrpc": "2.0", "id": 1, "method": "prana.get_state", "params": {"address": "XX:XX:XX:XX:XX:XX"} }'
Returns PranaState object. For baseline prana series (e.g.model 150, 200G) with no any sensors on board:
{
"result":{
"speed_locked":4,
"speed_in":4,
"speed_out":4,
"night_mode":false,
"auto_mode":false,
"flows_locked":true,
"is_on":false,
"mini_heating_enabled":false,
"winter_mode_enabled":false,
"is_input_fan_on":false,
"is_output_fan_on":false,
"brightness": 6,
"sensors": null,
"timestamp":"2020-11-18T23:14:45.313515"
},
"id":1,
"jsonrpc":"2.0"
}
For models with embedded sensors (e.g. Eco Life, Eco energy series):
{
"result":{
"speed_locked":4,
"speed_in":4,
"speed_out":4,
"night_mode":false,
"auto_mode":false,
"flows_locked":true,
"is_on":false,
"mini_heating_enabled":false,
"winter_mode_enabled":false,
"is_input_fan_on":false,
"is_output_fan_on":false,
"sensors": {
"temperature_in": 12.3,
"temperature_out": 9.6,
"humidity": 41,
"pressure": 1010,
"voc": 632.5,
"co2": 651.1
},
"timestamp":"2020-11-18T23:14:45.313515"
},
"id":1,
"jsonrpc":"2.0"
}
Method name: prana.set_state
Name | Type | Required | Description |
---|---|---|---|
address | string | yes | Mac address of the device to communicate with. Could be obtained from prana.discover query result |
state | object | yes | State to set for the device. The structure is listed below |
timeout | int | no | Time in seconds to wait for successful command execution. Default: 4s. |
attempts | int | no | Number of connection attempts to make before the failure Default: 5. |
The following properties could be set via Set State
Name | Type | Required | Description |
---|---|---|---|
speed | string | no | Either string representing integer (0-10) or one of "low", "l", "high", "h", "off", "stop", "2", "3", "4", "5", "6", "7", "8", "9" |
mode | string | no | One of normal, night, high . It doesn't seem to have any practical |
winter_mode | bool | no | Enable\disable winter mode (anti-frost) |
heating | bool | no | Enable\disable heating |
brightness | int | no | Set brightness. Should be an integer in a range of 1-6. See alsobrightness_pct |
brightness_pct | int | no | Set brightness in percent (0-100). Note: it's impossible to turn off screen so 0 will mean brightness level 1 |
Note: You should specify either brightness
or brightness_pct
but not both at the same time.
Example
{
"jsonrpc": "2.0",
"id": 1,
"method": "prana.set_state",
"params": {"address": "XX:XX:XX:XX:XX:XX", "state": {"speed": 1}}
}
Shell command
curl \
-X POST \
-H "Accept: application/json" \
http://YOUR_IP:8881/ \
-d '{ "jsonrpc": "2.0", "id": 1, "method": "prana.set_state", "params": {"address": "XX:XX:XX:XX:XX:XX", "state": {"speed": 1}} }'
Returns the PranaState object. See Get State method for more details on the object structure.
{
"result":{
"speed_locked": 1,
"speed_in": 1,
"speed_out": 1,
"brightness": 6,
"night_mode": true,
"auto_mode": false,
"flows_locked": true,
"is_on": true,
"mini_heating_enabled": false,
"winter_mode_enabled": false,
"is_input_fan_on": true,
"is_output_fan_on": true,
"sensors": null,
"timestamp": "2021-04-06T20:39:15.516925"
},
"id":1,
"jsonrpc":"2.0"
}
You could use any HTTP client to query the server. The underlying is JSON-RPCv2. The interface is defined here.
If you are looking for programmatic access from the python code you might consider the python API client. It has minimal dependencies and could be installed from the pip.
If your project is based on asyncio the recommended way is to use aiohttp based client:
pip install prana-rc.client[aiohttp]
Here is the basic usage example:
python TBD
The library could be used either directly in a python project or it could act as a server which maintains bluetooth connection with Prana device and exposes HTTP interface to the clients. See diagram below:
This approach is recommended as it brings some significant benefits over the embedding prana_rc into its own codebase:
- Stability. Prana RC uses bluetooth library which relies on low-level OS APIs. Theoretically, it might be a stability risk for your application. In case you use the prana server in case of a crash, it will not affect your application. If you use the Dockerized version it is easy to configure automatic restart.
- Coverage. Bluetooth works stable on a relatively small distance (5-10m with no obstacles) this means your server should be located close to the device. Often it is hard\impossible as you have a number of prana devices in different locations so the solution would be to set up a few intermediate nodes (e.g. some microcomputers like Raspberry Pi) with server components and connect them to the central control unit via API.
- Easy integration. There is no lock on particular technology so the library could be used in conjunction with any tech stack.
The device running this software must be equipped with a bluetooth 4.0+ module so it supports BLE. This module relies on Bleak library so there is a chance it might work on Win, Mac, and Linux. However, it was tested only on:
- Linux (x64): Fedora, Debian
- Raspbery PI: Raspbian
- Mac: Catalina
Most likely it is compatible with Prana 150,200G, and Eco Energy series (with a limited feature set). But the confirmed list of models which were verified to work fine is below:
- Prana 150
- Prana 160 (italian market)
Please, create a ticket if you tested it with another device model so we could extend the list.
- Using device password is not supported
- Reading information form built-in sensors (for Eco Energy series) is limited. At the moment VOC and CO2 sensors are not supported.
- Changing brightness is not supported
- Dmitry Berezovsky, author
- Bleak, bluetooth client library
- Contributors:
- @francesco-re-1107, eco-energy series support
This module is licensed under GPL v3. This means you are free to use in non-commercial projects.
The GPL license clearly explains that there is no warranty for this free software. Please see the included LICENSE file for details.