Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker support, mqtt bridge #6

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM ubuntu:18.04
MAINTAINER e1z0

RUN apt-get update && apt-get install -y software-properties-common language-pack-en-base python3 python3-pip nano python3-simplejson && \
export LC_ALL=en_US.UTF-8 && export LANG=en_US.UTF-8 && pip3 install pycrypto paho-mqtt && \
rm -rf /var/lib/apt/lists/* && rm -rf /var/cache/apk/*

COPY . /app

ENTRYPOINT ["/app/docker_init"]

11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
all: build

build:
docker build -t nbetest:latest -f Dockerfile --no-cache=true .
upload:
docker tag nbetest:latest nulldevil/nbetest:latest
docker push nulldevil/nbetest:latest
up:
COMPOSE_PROJECT_NAME=nbetest COMPOSE_IGNORE_ORPHANS=True docker-compose -f docker-compose.yml up -d
down:
COMPOSE_PROJECT_NAME=nbetest COMPOSE_IGNORE_ORPHANS=True docker-compose -f docker-compose.yml down
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
# Test program for the NBE pellet burner UDP protocol
# Test program and mqtt bridge for the NBE pellet burner UDP protocol

A client that can connect to a scotte V7/V13 controller (and apparently also aduro pellet hybrid stoves), and a test server that simulates a controller box.


## MQTT Bridge

<pre>
python mqtt-bridge.py -d
</pre>

Configuration lies in config.json, just modify to suit your needs also edit and copy pellet.service to /etc/systemd/system and start daemon
```
systemctl enable pellet&& systemctl start pellet
```

## MQTT Bridge using docker

```
make up (edit docker-compose.yml before)
```

## Home Assistant Integration

Just copy [pellet-burner.yaml](/pellet-burner.yaml) to your home assistant config directory and include in the main configuration.yaml file.
```
sensor: !include pellet-burner.yaml
```
You will have to restart Home Assistant.

<img src="https://github.com/e1z0/nbetest/raw/master/pics/pellet_burner_ha_info_pic.png" width=40% height=40%>


## Client

<pre>
Expand Down
19 changes: 10 additions & 9 deletions client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#! /usr/bin/python
#! /usr/bin/python3
# -*- coding: utf-8 -*-
"""
Copyright (C) 2013 Anders Nylund
Expand Down Expand Up @@ -72,14 +72,15 @@ def rawfunc(args, proxy):
parser_c.set_defaults(func=getfunc)

args = argparser.parse_args()

if args.address is None:
with Proxy.discover(args.password, PORT, args.serial) as proxy:
args.func(args, proxy)
else:
with Proxy(args.password, PORT, args.address, args.serial) as proxy:
args.func(args, proxy)

try:
if args.address is None:
with Proxy.discover(args.password, PORT, args.serial) as proxy:
args.func(args, proxy)
else:
with Proxy(args.password, PORT, args.address, args.serial) as proxy:
args.func(args, proxy)
except AttributeError:
print ("too few arguments")



Expand Down
11 changes: 11 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"nbe_serial": "55116",
"nbe_ip": "192.168.13.106",
"nbe_port": 8483,
"mqtt_server": "192.168.13.1",
"mqtt_port": 1883,
"mqtt_prefix": "pellet_burner",
"mqtt_client_name": "pellet-burner",
"refresh_rate": 60,
"options": [ "operating_data", "settings/boiler" ]
}
25 changes: 25 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: '2.4'
services:
nbetest:
container_name: nbetest
image: nulldevil/nbetest:latest
hostname: nbetest
restart: unless-stopped
environment:
NBE_SERIAL: "xxxx"
NBE_IP: "xxxxx"
NBE_PORT: "8483"
MQTT_IP: "192.168.1.x"
MQTT_PORT: "1883"
MQTT_PREFIX: "bellet_burner"
MQTT_CLIENT_NAME: "pellet-burner"
REFRESH_RATE: 5
cap_add:
- SYS_RESOURCE
networks:
- docker_intern


networks:
docker_intern:
external: true
23 changes: 23 additions & 0 deletions docker_init
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash


echo "Configuring..."

echo "{" > /app/config.json
echo "\"nbe_serial\": \"${NBE_SERIAL}\"," >> /app/config.json
echo "\"nbe_ip\": \"${NBE_IP}\"," >> /app/config.json
echo "\"nbe_port\": ${NBE_PORT}," >> /app/config.json
echo "\"mqtt_server\": \"${MQTT_IP}\"," >> /app/config.json
echo "\"mqtt_port\": ${MQTT_PORT}," >> /app/config.json
echo "\"mqtt_prefix\": \"${MQTT_PREFIX}\"," >> /app/config.json
echo "\"mqtt_client_name\": \"${MQTT_CLIENT_NAME}\"," >> /app/config.json
echo "\"refresh_rate\": ${REFRESH_RATE}," >> /app/config.json
echo "\"options\": [ \"operating_data\", \"settings/boiler\" ]" >> /app/config.json
echo "}" >> /app/config.json

echo "Config done."
cat /app/config.json

echo "Starting..."
cd /app
python3 /app/mqtt-bridge.py -d
6 changes: 3 additions & 3 deletions frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def decode(self, record):
i += 2
self.sequencenumber = int(record[i:i+2])
if self.sequencenumber != self.request.sequencenumber:
#print self.sequencenumber, self.request.sequencenumber
# print (self.sequencenumber, self.request.sequencenumber)
raise IOError
i += 2
self.status = int(record[i:i+1])
Expand All @@ -170,9 +170,9 @@ def decode(self, record):
i += 3
if not len(record) == self.size + self.RESPONSE_HEADER_SIZE:
raise IOError
#print record[i:i+self.size]
#print (record[i:i+self.size])
self.payload = (record[i:i+self.size]).decode('ascii')
#print self.payload
#print (self.payload)
i += self.size
if not record[i] == END[0]:
raise IOError
Expand Down
90 changes: 90 additions & 0 deletions mqtt-bridge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#! /usr/bin/python3
# -*- coding: utf-8 -*-
"""
NBE to MQTT (c) 2021 e1z0
NBE Protocol Reverse Engineering Copyright (C) 2013 Anders Nylund

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from __future__ import print_function
from argparse import ArgumentParser
from protocol import Proxy
#import simplejson as json
import json
import os
import paho.mqtt.client as paho
import time

PASSWORD = '0123456789' # not necessary at all :)

def mqtt_topic(config,topic,val):
client = paho.Client(config["mqtt_client_name"])
client.connect(config["mqtt_server"],config["mqtt_port"])
client.publish(config["mqtt_prefix"]+"/"+topic,val)

def query_boiler(config):
print ("Making query to the pellet burner...")
if config["nbe_ip"] is None:
with Proxy.discover(PASSWORD, config["nbe_port"], config["nbe_serial"]) as proxy:
for query in config["options"]:
response = proxy.get(query)
for item in response:
val = item.split("=",1)
#for debug purposes #print ("Key: %s => val: %s" % (val[0],val[1]))
mqtt_topic(config,val[0],val[1])
else:
with Proxy(PASSWORD, config["nbe_port"], config["nbe_ip"], config["nbe_serial"]) as proxy:
for query in config["options"]:
response = proxy.get(query)
for item in response:
val = item.split("=",1)
#for debug purposes #print ("Key: %s => val: %s" % (val[0],val[1]))
mqtt_topic(config,val[0],val[1])

def help():
print ("Just a simple mqtt bridge that publishes pellet burner info data to mqtt")

def daemon():
print ("daemon mode")
curr_path = os.path.dirname(os.path.realpath(__file__))
config_file = curr_path+"/config.json"
print ("Checking if exists:",config_file)
if (os.path.exists(config_file)):
with open(config_file) as f:
config = json.load(f)
print ("Settings loaded...")
while(not time.sleep(config["refresh_rate"])):
try:
query_boiler(config)
except:
print ("Maybe we got some interruption with pallet burner connection or something have failed, continuing anyways...")
else:
print ("Settings file "+config_file+" does not exist!")

if __name__ == '__main__':

argparser = ArgumentParser()
argparser.add_argument('-d','--daemon', default=None, action='store_true')
args = argparser.parse_args()
try:
if args.daemon is None:
help()
else:
daemon()
except AttributeError:
print ("too few arguments")




88 changes: 88 additions & 0 deletions pellet-burner.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
- platform: mqtt
state_topic: "pellet_burner/settings/boiler/temp"
name: "Pellet burner max temperature"
unique_id: "pellet_burner_max_temp"
state_class: measurement
device_class: temperature
unit_of_measurement: °C
- platform: mqtt
state_topic: "pellet_burner/operating_data/boiler_temp"
name: "Pellet burner current temperature"
unique_id: "pellet_burner_current_temp"
state_class: measurement
device_class: temperature
unit_of_measurement: °C
- platform: mqtt
state_topic: "pellet_burner/operating_data/external_temp"
name: "Pellet burner external temperature"
unique_id: "pellet_burner_ext_temp"
state_class: measurement
device_class: temperature
unit_of_measurement: °C
- platform: mqtt
state_topic: "pellet_burner/operating_data/cloud_level"
name: "Pellet burner external clouds"
unique_id: "pellet_burner_ext_clouds"
state_class: measurement
unit_of_measurement: '%'
- platform: mqtt
state_topic: "pellet_burner/operating_data/power_kw"
name: "Pellet burner power kwh"
unique_id: "pellet_burner_power_kwh"
state_class: measurement
device_class: power
unit_of_measurement: 'kW'
- platform: mqtt
state_topic: "pellet_burner/operating_data/power_pct"
name: "Pellet burner power percent"
unique_id: "pellet_burner_power_percent"
state_class: measurement
device_class: power_factor
unit_of_measurement: '%'
- platform: mqtt
state_topic: "pellet_burner/operating_data/oxygen"
name: "Pellet burner oxygen percent"
unique_id: "pellet_burner_oxygen_percent"
state_class: measurement
device_class: power_factor
unit_of_measurement: '%'
- platform: mqtt
state_topic: "pellet_burner/operating_data/oxygen_ref"
name: "Pellet burner oxygen ref percent"
unique_id: "pellet_burner_oxygen_ref_percent"
state_class: measurement
device_class: power_factor
- platform: mqtt
state_topic: "pellet_burner/operating_data/photo_level"
name: "Pellet burner photo sensor"
unique_id: "pellet_burner_photo_sensor"
state_class: measurement
device_class: illuminance
unit_of_measurement: 'lm'
- platform: mqtt
state_topic: "pellet_burner/operating_data/forward_ref"
name: "Pellet burner zone1 wanted"
unique_id: "pellet_burner_zone1_wanted"
state_class: measurement
device_class: temperature
unit_of_measurement: °C
- platform: mqtt
state_topic: "pellet_burner/operating_data/forward_temp"
name: "Pellet burner zone1 actual flow"
unique_id: "pellet_burner_zone1_actual_flow"
state_class: measurement
device_class: temperature
unit_of_measurement: °C
- platform: mqtt
state_topic: "pellet_burner/operating_data/house_valve_state"
name: "Pellet burner zone1 valve position"
unique_id: "pellet_burner_zone1_valve_position"
state_class: measurement
device_class: power_factor
unit_of_measurement: '%'
- platform: mqtt
state_topic: "pellet_burner/operating_data/content"
name: "Pellet burner total burned"
unique_id: "pellet_burner_total_burned"
state_class: measurement
unit_of_measurement: 'kg'
17 changes: 17 additions & 0 deletions pellet.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[Unit]
Description=Pellet burner MQTT bridge
After=network.target auditd.service ssh.service


[Service]
Type=simple
User=root
WorkingDirectory=/root/nbetest
ExecStart=/usr/bin/python3 /root/nbetest/mqtt-bridge.py -d
Restart=always
RestartSec=10
KillMode=process


[Install]
WantedBy=multi-user.target
Binary file added pics/pellet_burner_ha_info_pic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading