A Pypi library to communicate with Aduro (H1) wood/pellet burner via NBE communication.
This library is intented to communicate with NBE capable burners (typically Adura hybrid stoves).
NBE is an UDP protocol that uses ASCII frames to communicate. Here is an example frame (this one is used to discover a burner):
abcdefghijkl041837 \x02000012345678904361465775pad 013NBE Discovery\x04
And here the different part of the frame:
- abcdefghijkl -
appId
, 12 alphanumerical (upper and lowercase) characters - Uniquely identify the application that is talking with the oven (you can put here whatever you want) - 123456 -
controllerId
, 6 digits - This is the "Serial number" of your oven (the same as the one you entered in the official Aduro application, you can find it on a sticker on the oven, often inside of the door) - space or * or - - Encryption level of the frame (' ' = not encrypted, '*' = RSA encrypted, '-' = XTEA encrypted)
- \x02 -
startChar
, the ASCII character0x02
(so 1 char, not "\x02") - This is the separator to identify the beginning of the request - 00 -
function
, 2 digits - Identify the type of request (see below) - 00 -
sequenceNumber
, 2 digits - To identify the request when run in sequence (optional, you can leave this at 00 if you don't care about the order of your requests) - 1234567890 -
pinCode
, 10 digit - The password to connect to your oven (the same as the one you entered in the official Aduro application, you can find it on a sticker on the oven, often inside of the door) - 4361465775 -
time
, 10 digits - The timestamp at which the request as been issued ('{:0>10.10}'.format(str(time()))
in Python do the trick) - pad _(literally the string "pad ") - Extra space reserved for future use
- 013 -
payloadSize
, 3 digits - The size of the actual payload of the request (that comes right after this) - NBE Discovery -
payload
, max 495 bytes - The actual payload of the request (here in the example it's a discovery request). - \x04 -
endChar
, the ASCII character0x04
(so 1 char, not "\x04") - This is the separator to identify the end of the payload
A response will always be formed in pretty much the same way:
abcdefghijkl123456\x0200000065Serial=123456;IP=192.168.1.250;Type=v13std;Ver=705;Build=38;Lang=0\x04
- abcdefghijkl -
appId
, 12 alphanumerical (upper and lowercase) characters - Uniquely identify the application that the oven is talking to - 123456 -
controllerId
, 6 digits - This is the "Serial number" of the oven responding - \x02 -
startChar
, the ASCII character0x02
(so 1 char, not "\x02") - This is the separator to identify the beginning of the response - 00 -
function
, 2 digits - Identify the type of response (see below) - 00 -
sequenceNumber
, 2 digits - To identify the request this response is for when using a sequence - 0 -
status
, 1 digit - The status of the response (0 = success, >0 = error) - 013 -
payloadSize
, 3 digits - The size of the actual payload of the response (that comes right after this) - Serial=12345;IP=192.168.1.250;Type=v13std;Ver=705;Build=38;Lang=0 -
payload
, max 1007 bytes - The actual payload of the response (here in the example it's a discovery response in the form of a semicolon separated list of key/values pair). - \x04 -
endChar
, the ASCII character0x04
(so 1 char, not "\x04") - This is the separator to identify the end of the payload
There is a limited set of functions you can use in the NBE protocol:
- 0: Discovery
- 1: Read settings value
- 2: Set settings value
- 3: Read setup range
- 4: Read operating data
- 5: Read advanced data
- 6: Read consumption data
- 7: Read chart data
- 8: Read event log
- 9: Read info
- 10: Read available programs
Note that your burner might not support all of them and might also support others (for example,
11
is a supported type on Aduro H1 burners).
You can learn more about NBE with this repository (I highly recommend you to play with the CLI to discover more about the protocol) and in particular this documentation as well as the various implementations.
You can also read this issue and the implementation of the protocol in the PyDuro library.
pip install pyduro
Simply import the actions and use them:
from pyduro.actions import discover, get, set, raw
discover.run()
get.run(
burner_address="<burner IP address>",
serial="<burner serial number>",
pin_code="<burner pin code>",
function_name="<settings|range|operating|advanced|consumption|chart|logs|info|versions>",
path="<path>"
)
set.run(
burner_address="<burner IP address>",
serial="<burner serial number>",
pin_code="<burner pin code>",
path="<path>"
value="<value>"
)
raw.run(
burner_address="<burner IP address>",
serial="<burner serial number>",
pin_code="<burner pin code>",
function_id="<function ID>",
payload="<payload>"
)
Every response from a burner will be composed with the same fields:
frame
: the whole raw NBE frame receivedburner_address
: the burner IP address from which the response originatedburner_port
: the burner UDP port from which the response originatedapp_id
: the application ID the response is intended to (when using PyDuro will always be___pyduro___
)serial
: the burner serial number from which the response originatedfunction
: the function identifier the response is intended tosequence_number
: the identifier of the request the response is intended tostatus
: the status of the response (0 = success, >0 = error)payload_size
: the size of the payload of the responsepayload
: the actual response payload
You can also use the parse_payload
method that will return:
- a string if the payload is a string
- a dict if the payload is a semicolon separated list of fields (
name=value
) - a list of the payload is a semicolon separated list of values
python -m pyduro --help
python -m pyduro [discover]
The CLI will exit with 0 if a burner is found, 1 otherwise.
python -m pyduro -b <burner IP address> -s <burner serial number> -p <burner pin code> get <settings|range|operating|advanced|consumption|chart|logs|info|versions> "<path>"
The result will be output as a JSON object that you can then manipulate with
jq
for example.
The CLI will exit with the return code return by the burner (0 = success, >0 = error).
For
logs
action, you can pass "now" as path (which is also the default value) to get the latest logs from your burner.
For
settings
action, you have to pass one of the valid following path:
- "boiler",
- "hot_water"
- "regulation"
- "weather"
- "weather2"
- "oxygen"
- "cleaning"
- "hopper"
- "fan"
- "auger"
- "ignition"
- "pump"
- "sun"
- "vacuum"
- "misc"
- "alarm"
- "manual"
To see all sub element of a path, add
.*
at the end of the path.
To see a specific element of a path, add.<element name>
at the end of the path.
For
consumption
action, you can pass one of the following path:
- "total_hours",
- "total_days"
- "total_months"
- "total_years"
- "dhw_hours"
- "dhw_days"
- "dhw_months"
- "dhw_years"
- "counter"
Examples
python -m pyduro -b 192.168.1.250 -s 1234 -p 12345678 get operating
> {
> "NA": "38",
> "air_flow": "0",
> "air_quality": "0",
> "ashbox_contact": "0.0",
> "ashbox_minutes": "0.0",
> "back_pressure": "0",
> "boiler_pump_state": "0",
> "boiler_ref": "19.0",
> [...]
> }
python -m pyduro -b 192.168.1.250 -s 1234 -p 12345678 get operating "boiler_ref"
> "boiler_ref=19.0"
python -m pyduro -b 192.168.1.250 -s 1234 -p 12345678 get settings "misc.*"
> {
> [...]
> "start": "0",
> "stop": "0",
> [...]
> }
python -m pyduro -b 192.168.1.250 -s 1234 -p 12345678 get settings "misc.start"
> "start=0"
Note that you can pass "" as a path to get the full response from your burner.
If you don't give a pass (or give an empty one) then "" will be used as default.
python -m pyduro -b <burner IP address> -s <burner serial number> -p <burner pin code> set "<path>" "<value>"
The CLI will exit with the return code return by the burner (0 = success, >0 = error).
Examples
python -m pyduro -b 192.168.1.250 -s 1234 -p 12345678 set "misc.start" "1"
python -m pyduro -b 192.168.1.250 -s 1234 -p 12345678 set "misc.stop" "1"