Neue Hauptversion 4.1 - Smashing Pumpkin verfügbar
NEU! Gebäudeinformationssystem
NEU! Neun neue Logikmodule
NEU! Zwei neue VISU Widgets für Energiefluss und Navigation
NEU! Info- und Schalten-Widget in V2 mit umfassender Erweiterung Schalten und Aussenden
Umfassende Überarbeitung des Logik Managers
Erweiterung des Backup-Moduls für Migration von 2500/2600 TWS
Verbesserter Timberwolf Systemmonitor
Und viele weitere Verbesserungen
Alle Informationen hier: https://elabnet.atlassian.net/wiki/x/AQCRn
NEU! Gebäudeinformationssystem
NEU! Neun neue Logikmodule
NEU! Zwei neue VISU Widgets für Energiefluss und Navigation
NEU! Info- und Schalten-Widget in V2 mit umfassender Erweiterung Schalten und Aussenden
Umfassende Überarbeitung des Logik Managers
Erweiterung des Backup-Moduls für Migration von 2500/2600 TWS
Verbesserter Timberwolf Systemmonitor
Und viele weitere Verbesserungen
Alle Informationen hier: https://elabnet.atlassian.net/wiki/x/AQCRn
[Beantwortet] V-Bus Anbindung an den TWS
Forumsregeln
- Denke bitte an aussagekräftige Titel und gebe dort auch die [Firmware] an. Wenn ETS oder CometVisu beteiligt sind, dann auch deren Version
- Bitte mache vollständige Angaben zu Deinem Server, dessen ID und dem Online-Status in Deiner Signatur. Hilfreich ist oft auch die Beschreibung der angeschlossener Hardware sowie die verwendeten Protokolle
- Beschreibe Dein Projekt und Dein Problem bitte vollständig. Achte bitte darauf, dass auf Screenshots die Statusleiste sichtbar ist
- Bitte sei stets freundlich und wohlwollend, bleibe beim Thema und unterschreibe mit deinem Vornamen. Bitte lese alle Regeln, die Du hier findest: https://wiki.timberwolf.io/Forenregeln
-
- Reactions:
- Beiträge: 530
- Registriert: Mo Dez 02, 2019 5:38 am
- Wohnort: Freital
- Hat sich bedankt: 418 Mal
- Danksagung erhalten: 230 Mal
V-Bus Anbindung an den TWS
Hallo zusammen
Bei mir im Haus arbeitet eine Erdwärmepumpe Viessmann Vitocal 300 mit Vitocell 200 Steuerung und eine Frischwasserstation Vitotrans 353. leider ist das Modbusmodul von Viessmann mit 1000€ ganz schön teuer und aus der Frischwasserstation bekommt man die Werte nur über den VBus (Viessmann interner Bus)
http://hobbyelektronik.org/w/index.php/VBus-Decoder
Hier gibt es auch die Spezifikationen für den VBus.
Hat sich damit evtl schon mal jemand auseinander gesetzt bzw. Hat eine Idee das ganze Inman den TWS abzubinden?
Der ioBroker Adapter läuft dieser gibt aber leider keine Werte der Frischwasserstation aus.
Danke für eure Ideen
Bei mir im Haus arbeitet eine Erdwärmepumpe Viessmann Vitocal 300 mit Vitocell 200 Steuerung und eine Frischwasserstation Vitotrans 353. leider ist das Modbusmodul von Viessmann mit 1000€ ganz schön teuer und aus der Frischwasserstation bekommt man die Werte nur über den VBus (Viessmann interner Bus)
http://hobbyelektronik.org/w/index.php/VBus-Decoder
Hier gibt es auch die Spezifikationen für den VBus.
Hat sich damit evtl schon mal jemand auseinander gesetzt bzw. Hat eine Idee das ganze Inman den TWS abzubinden?
Der ioBroker Adapter läuft dieser gibt aber leider keine Werte der Frischwasserstation aus.
Danke für eure Ideen
Grüße Micha
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
Hallo Micha,
ich habe meine Oventrop Regumaq Frischwasserstation, die ebenfalls Resol V-Bus spricht über den Resol USB-Schnittstellenadapter an den TWS angebunden.
Darauf läuft im Docker Container das Python-Script von rellit (https://github.com/rellit/resol-vbus-python), welches ich um eine MQTT-Anbindung in Python (paho-mqtt) erweitert habe. Damit werden die Daten des V-Bus ausgelesen und über MQTT an den TWS in die Timeseries gesendet.
Das Vorlage-Script muss angepasst werden, da vermutlich auch die Viessmann-spezifischen Paket-Header (wie auch bei Oventrop) nicht standardmäßig interpretiert werden können. Über den Schnittstellenadapter am PC lässt sich mit der Resol Service Center Software (https://www.resol.de/de/software) allerdings der Datenstrom in Rohform ausgeben und die von deiner WP/FriWa genutzten Paketheader mit der V-Bus Spezifikation (http://danielwippermann.github.io/resol-vbus/#/vsf) abgeglichen werden. Siehe dazu auch die von dir bereits verlinkte Seite von Hobbyelektronik. Mit diesen Infos kann dann das Python Script angepasst werden.
Viel Erfolg.
Gruß Moritz
Hier die angepassten Scripte als Lösungsansatz
config.py
resol3mqtt.py
spec/Regumaq-X45.json
Hier noch der Docker Bauplan für das Image, basierend auf python-slim
die pyhton-scripts sind als persitenters Volume unter /app gemountet
ich habe meine Oventrop Regumaq Frischwasserstation, die ebenfalls Resol V-Bus spricht über den Resol USB-Schnittstellenadapter an den TWS angebunden.
Darauf läuft im Docker Container das Python-Script von rellit (https://github.com/rellit/resol-vbus-python), welches ich um eine MQTT-Anbindung in Python (paho-mqtt) erweitert habe. Damit werden die Daten des V-Bus ausgelesen und über MQTT an den TWS in die Timeseries gesendet.
Das Vorlage-Script muss angepasst werden, da vermutlich auch die Viessmann-spezifischen Paket-Header (wie auch bei Oventrop) nicht standardmäßig interpretiert werden können. Über den Schnittstellenadapter am PC lässt sich mit der Resol Service Center Software (https://www.resol.de/de/software) allerdings der Datenstrom in Rohform ausgeben und die von deiner WP/FriWa genutzten Paketheader mit der V-Bus Spezifikation (http://danielwippermann.github.io/resol-vbus/#/vsf) abgeglichen werden. Siehe dazu auch die von dir bereits verlinkte Seite von Hobbyelektronik. Mit diesen Infos kann dann das Python Script angepasst werden.
Viel Erfolg.
Gruß Moritz
Hier die angepassten Scripte als Lösungsansatz
config.py
Code: Alles auswählen
import os
# configure kind of connection "lan", "serial" or "stdin"
#connection = "lan"
connection = "serial"
#connection = "stdin"
# only used for "lan"
address = ("192.168.1.253", 7053)
vbus_pass = "vbus"
# only used for "serial"
port = "/dev/ttyACM0"
baudrate = 9600
spec_file = os.path.dirname(__file__) + '/spec/Regumaq-X45.json'
# expected amount of different source packets (see spec_file)
expected_packets = 1
debug = False
# MQTT Broker config
mqtt_host = "192.168.3.11"
#MQTT_PORT = 1883
#MQTT_KEEPALIVE_INTERVAL = 45
mqtt_topic = "regumaq"
Code: Alles auswählen
#!/usr/bin/env python3
#
# Talk with Resol VBUS over LAN or serial UART
#
import socket
import sys
import json
from decimal import *
import paho.mqtt.client as mqtt
import time
# Load settings
try:
import config
except:
sys.exit("config.py not found!")
if config.connection == "serial":
# import serial (pyserial) only if it's configured to not force installing it without needing
import serial
# Load Message specification
try:
import spec
except:
sys.exit("Could not load Message Specification")
# Logs in onto the DeltaSol BS Plus over LAN. Also starts (and maintains) the
# actual stream of data.
def login():
dat = recv()
#Check if device answered
if dat != "+HELLO\n":
return False
#Send Password
send("PASS %s\n" % config.vbus_pass)
dat = recv()
return dat.startswith("+OK")
def load_data():
if config.connection == "lan":
#Request Data
send("DATA\n")
dat = recv()
#Check if device is ready to send Data
if not dat.startswith("+OK"):
return
while len(result) < config.expected_packets:
buf = readstream()
msgs = splitmsg(buf)
if config.debug:
print(str(len(msgs))+" Messages, "+str(len(result))+" Resultlen")
for msg in msgs:
if config.debug: print(get_protocolversion(msg))
if "PV1" == get_protocolversion(msg):
if config.debug: print(format_message_pv1(msg))
parse_payload(msg)
elif "PV2" == get_protocolversion(msg):
if config.debug: print(format_message_pv2(msg))
# Receive 1024 bytes from stream
def recv():
if config.connection == "serial":
# timeout needs to be set to 0 (see init), or it will
# block until the requested number of bytes is read
dat = sock.read(1024)
elif config.connection == "lan":
dat = sock.recv(1024)
elif config.connection == "stdin":
dat = sock.buffer.read(1024)
else:
sys.exit('Unknown connection type. Please check config.')
return dat
# Sends given bytes over the stream. Adds debug
def send(dat):
sock.send(dat)
# Read data until minimum 1 message is received
# We cyclic get:
# '0xaa' '0x00' '0x00' '0x21' '0x74' '0x20' ...
# '0xaa' '0x15' '0x00' '0x21' '0x74' '0x10' ...
# '0xaa' '0x10' '0x00' '0x21' '0x74' '0x10' ...
# Only the last one is needed, so we need 4 times '0xaa'!
def readstream():
data = bytearray(b'')
data.extend(recv())
while data.count(0xAA) < 4:
data.extend(recv())
return data
#Split Messages on Sync Byte
def splitmsg(buf):
return buf.split(b'\xAA')[1:-1]
# Format 1 byte as String Hex string
def format_byte(byte):
return '0x' + ('0' if byte < 0x10 else '') + format(byte, 'x')
# Extract protocol Version from msg
def get_protocolversion(msg):
if msg[4] == 0x10: return "PV1"
if msg[4] == 0x20: return "PV2"
if msg[4] == 0x30: return "PV3"
return "UNKNOWN"
# Extract Destination from msg
def get_destination(msg):
return format_byte(msg[1]) + format_byte(msg[0])[2:]
#Extract source from msg
def get_source(msg):
return format_byte(msg[3]) + format_byte(msg[2])[2:]
# Extract command from msg
def get_command(msg):
return format_byte(msg[6]) + format_byte(msg[5])[2:]
# Get count of frames in msg
def get_frame_count(msg):
return gb(msg, 7, 8)
# Extract payload from msg
def get_payload(msg):
payload = bytearray(b'')
for i in range(get_frame_count(msg)):
payload.extend(integrate_septett(msg[9+(i*6):15+(i*6)]))
return payload
# parse payload and put result in result
def parse_payload(msg):
payload = get_payload(msg)
if config.debug:
print('ParsePacket Payload '+str(len(payload)))
for packet in spec.spec['packet']:
if packet['source'].lower() == get_source(msg).lower() and \
packet['destination'].lower() == get_destination(msg).lower() and \
packet['command'].lower() == get_command(msg).lower():
result[get_source_name(msg)] = {}
for field in packet['field']:
result[get_source_name(msg)][field['name'][0]] = str(
gb(payload, field['offset'], int(field['offset'])+((int(field['bitSize'])+1) / 8)) *
(Decimal(field['factor']) if 'factor' in field else 1)) + \
(field['unit'] if 'unit' in field else '')
def format_message_pv1(msg):
parsed = "PARSED: \n"
parsed += " ZIEL".ljust(15,'.')+": " + get_destination(msg) + "\n"
parsed += " QUELLE".ljust(15,'.')+": " + get_source(msg) + " " + get_source_name(msg) + "\n"
parsed += " PROTOKOLL".ljust(15,'.')+": " + get_protocolversion(msg) + "\n"
parsed += " BEFEHL".ljust(15,'.')+": " + get_command(msg) + "\n"
parsed += " ANZ_FRAMES".ljust(15,'.')+": " + str(get_frame_count(msg)) + "\n"
parsed += " CHECKSUM".ljust(15,'.')+": " + format_byte(msg[8]) + "\n"
for i in range(get_frame_count(msg)):
integrated = integrate_septett(msg[9+(i*6):15+(i*6)])
parsed += (" NB"+str(i*4+1)).ljust(15,'.')+": " + format_byte(msg[9+(i*6)]) + " - " + format_byte(integrated[0]) + "\n"
parsed += (" NB"+str(i*4+2)).ljust(15,'.')+": " + format_byte(msg[10+(i*6)]) + " - " + format_byte(integrated[1]) + "\n"
parsed += (" NB"+str(i*4+3)).ljust(15,'.')+": " + format_byte(msg[11+(i*6)]) + " - " + format_byte(integrated[2]) + "\n"
parsed += (" NB"+str(i*4+4)).ljust(15,'.')+": " + format_byte(msg[12+(i*6)]) + " - " + format_byte(integrated[3]) + "\n"
parsed += (" SEPTETT"+str(i+1)).ljust(15,'.')+": " + format_byte(msg[13+(i*6)]) + "\n"
parsed += (" CHECKSUM"+str(i+1)).ljust(15,'.')+": " + format_byte(msg[14+(i*6)]) + "\n"
parsed += " PAYLOAD".ljust(15,'.')+": " + (" ".join(format_byte(b) for b in get_payload(msg)))+"\n"
return parsed
def format_message_pv2(msg):
parsed = "PARSED: \n"
parsed += " ZIEL1".ljust(15,'.')+": " + format_byte(msg[0]) + "\n"
parsed += " ZIEL2".ljust(15,'.')+": " + format_byte(msg[1]) + "\n"
parsed += " QUELLE1".ljust(15,'.')+": " + format_byte(msg[2]) + "\n"
parsed += " QUELLE2".ljust(15,'.')+": " + format_byte(msg[3]) + "\n"
parsed += " PROTOKOLL".ljust(15,'.')+": " + format_byte(msg[4]) + "\n"
parsed += " BEFEHL1".ljust(15,'.')+": " + format_byte(msg[5]) + "\n"
parsed += " BEFEHL2".ljust(15,'.')+": " + format_byte(msg[6]) + "\n"
parsed += " ID1".ljust(15,'.')+": " + format_byte(msg[7]) + "\n"
parsed += " ID2".ljust(15,'.')+": " + format_byte(msg[8]) + "\n"
parsed += " WERT1".ljust(15,'.')+": " + format_byte(msg[9]) + "\n"
parsed += " WERT2".ljust(15,'.')+": " + format_byte(msg[10]) + "\n"
parsed += " WERT3".ljust(15,'.')+": " + format_byte(msg[11]) + "\n"
parsed += " WERT4".ljust(15,'.')+": " + format_byte(msg[12]) + "\n"
parsed += " SEPTETT".ljust(15,'.')+": " + format_byte(msg[13]) + "\n"
parsed += " CHECKSUM".ljust(15,'.')+": " + format_byte(msg[14]) + "\n"
return parsed
def get_compare_length(mask):
i = 1
while i < 6 and mask[i] != '0':
i += 1
return i+1
def get_source_name(msg):
src = format_byte(msg[3]) + format_byte(msg[2])[2:]
for device in spec.spec['device']:
if src[:get_compare_length(device['mask'])].lower() == device['address'][:get_compare_length(device['mask'])].lower():
return device['name'] if get_compare_length(device['mask']) == 7 else str(device['name']).replace('#',device['address'][get_compare_length(device['mask'])-1:],1)
return ""
def integrate_septett(frame):
data = bytearray(b'')
septet = frame[4]
for j in range(4):
if septet & (1 << j):
data.append(frame[j] | 0x80)
else:
data.append(frame[j])
return data
# Gets the numerical value of a set of bytes (respect Two's complement by value Range)
def gb(data, begin, end): # GetBytes
# convert begin and end to int whatever was passed to make enumerate work
begin = int(begin)
end = int(end)
wbg = sum([0xff << (i * 8) for i, b in enumerate(data[begin:end])])
s = sum([b << (i * 8) for i, b in enumerate(data[begin:end])])
if s >= wbg/2:
s = -1 * (wbg - s)
return s
if __name__ == '__main__':
if config.connection == "serial":
sock = serial.Serial(config.port, baudrate=config.baudrate, timeout=0)
elif config.connection == "lan":
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(config.address)
login()
elif config.connection == "stdin":
sock = sys.stdin
else:
sys.exit('Unknown connection type. Please check config.')
while True:
result = dict()
load_data()
client = mqtt.Client("resol")
# client.connect(mqtt_host)
client.connect("192.168.3.11")
#print(json.dumps(result))
# client.publish(mqtt_topic,json.dumps(result))
client.publish("regumaq",json.dumps(result))
client.publish("regumaq/temperaturen/S1",str(result["Regumaq-X45"]["Temperatur Sensor 1"].split(" ",1)[0]))
client.publish("regumaq/temperaturen/s2",str(result["Regumaq-X45"]["Temperatur Sensor 2"].split(" ",1)[0]))
client.publish("regumaq/temperaturen/s3",str(result["Regumaq-X45"]["Temperatur Sensor 3"].split(" ",1)[0]))
client.publish("regumaq/temperaturen/s4",str(result["Regumaq-X45"]["Temperatur Sensor 4"].split(" ",1)[0]))
client.publish("regumaq/temperaturen/s5",str(result["Regumaq-X45"]["Temperatur Sensor 5"].split(" ",1)[0]))
client.publish("regumaq/temperaturen/s6",str(result["Regumaq-X45"]["Temperatur Sensor 6"].split(" ",1)[0]))
client.publish("regumaq/temperaturen/s7",str(result["Regumaq-X45"]["Temperatur Sensor 7"].split(" ",1)[0]))
client.publish("regumaq/temperaturen/s8",str(result["Regumaq-X45"]["Temperatur Sensor 8"].split(" ",1)[0]))
client.publish("regumaq/volumentstrom/trinkwasser",str(result["Regumaq-X45"]["Durchflusssensor"].split(" ",1)[0]))
client.publish("regumaq/pwm/pwm1",str(result["Regumaq-X45"]["Spannung PWM 1.1"].split(" ",1)[0]))
client.publish("regumaq/pwm/pwm2",str(result["Regumaq-X45"]["Spannung PWM 1.2"].split(" ",1)[0]))
client.publish("regumaq/pwm/pwm3",str(result["Regumaq-X45"]["Spannung PWM 2.1"].split(" ",1)[0]))
client.publish("regumaq/pwm/pwm4",str(result["Regumaq-X45"]["Spannung PWM 2.2"].split(" ",1)[0]))
client.publish("regumaq/relais/R1",str(result["Regumaq-X45"]["Relais 1"].split(" ",1)[0]))
client.publish("regumaq/relais/R2",str(result["Regumaq-X45"]["Relais 2"].split(" ",1)[0]))
client.publish("regumaq/relais/R3",str(result["Regumaq-X45"]["Relais 3"].split(" ",1)[0]))
client.publish("regumaq/relais/R4",str(result["Regumaq-X45"]["Relais 4"].split(" ",1)[0]))
client.publish("regumaq/ausgaenge/A1",str(result["Regumaq-X45"]["Ausgang 1"].split(" ",1)[0]))
client.publish("regumaq/ausgaenge/A2",str(result["Regumaq-X45"]["Ausgang 2"].split(" ",1)[0]))
client.publish("regumaq/ausgaenge/A3",str(result["Regumaq-X45"]["Ausgang 3"].split(" ",1)[0]))
client.publish("regumaq/ausgaenge/A4",str(result["Regumaq-X45"]["Ausgang 4"].split(" ",1)[0]))
client.publish("regumaq/ausgaenge/LinOut",str(result["Regumaq-X45"]["Lin Out"].split(" ",1)[0]))
client.publish("regumaq/fehler/s1",str(result["Regumaq-X45"]["Fehler S1"]))
client.publish("regumaq/fehler/s2",str(result["Regumaq-X45"]["Fehler S2"]))
client.publish("regumaq/fehler/s3",str(result["Regumaq-X45"]["Fehler S3"]))
client.publish("regumaq/fehler/s4",str(result["Regumaq-X45"]["Fehler S4"]))
client.publish("regumaq/fehler/s5",str(result["Regumaq-X45"]["Fehler S5"]))
client.publish("regumaq/fehler/s6",str(result["Regumaq-X45"]["Fehler S6"]))
client.publish("regumaq/fehler/s7",str(result["Regumaq-X45"]["Fehler S7"]))
client.publish("regumaq/fehler/s8",str(result["Regumaq-X45"]["Fehler S8"]))
client.disconnect()
time.sleep(10)
if config.connection == "lan":
try:
sock.shutdown(0)
except:
pass
sock.close()
sock = None
spec/Regumaq-X45.json
Code: Alles auswählen
{
"vbusSpecification": {
"device": [
{
"address": "0x1632",
"mask": "0xFFFF",
"name": "Regumaq-X45",
"isMaster": "true"
}
],
"packet": [
{
"destination": "0x0010",
"source": "0x1632",
"command": "0x0100",
"field": [
{
"offset": "0",
"name": [
"Temperatur Sensor 1",
{
"-lang": "en",
"#text": "Temperature sensor 1"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "2",
"name": [
"Temperatur Sensor 2",
{
"-lang": "en",
"#text": "Temperature sensor 2"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "4",
"name": [
"Temperatur Sensor 3",
{
"-lang": "en",
"#text": "Temperature sensor 3"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "6",
"name": [
"Temperatur Sensor 4",
{
"-lang": "en",
"#text": "Temperature sensor 4"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "8",
"name": [
"Temperatur Sensor 5",
{
"-lang": "en",
"#text": "Temperature sensor 5"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "10",
"name": [
"Temperatur Sensor 6",
{
"-lang": "en",
"#text": "Temperature sensor 6"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "12",
"name": [
"Temperatur Sensor 7",
{
"-lang": "en",
"#text": "Temperature sensor 7"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "14",
"name": [
"Temperatur Sensor 8",
{
"-lang": "en",
"#text": "Temperature sensor 8"
}
],
"bitSize": "15",
"factor": "0.1",
"unit": " °C"
},
{
"offset": "16",
"name": [
"Spannung PWM 1.1",
{
"-lang": "en",
"#text": "Voltage / GFA 1.1"
}
],
"bitSize": "32",
"factor": "0.000001",
"unit": " V"
},
{
"offset": "20",
"name": [
"Spannung PWM 1.2",
{
"-lang": "en",
"#text": "Voltage / GFA 1.2"
}
],
"bitSize": "32",
"factor": "0.000001",
"unit": " V"
},
{
"offset": "24",
"name": [
"Spannung PWM 2.1",
{
"-lang": "en",
"#text": "Voltage / GFA 2.1"
}
],
"bitSize": "32",
"factor": "0.000001",
"unit": " V"
},
{
"offset": "28",
"name": [
"Spannung PWM 2.2",
{
"-lang": "en",
"#text": "Voltage / GFA 2.2"
}
],
"bitSize": "32",
"factor": "0.000001",
"unit": " V"
},
{
"offset": "32",
"name": [
"Durchflusssensor",
{
"-lang": "en",
"#text": "Frequency Sensor"
}
],
"bitSize": "15",
"unit": " l/h"
},
{
"offset": "35",
"name": [
"Relais 1",
{
"-lang": "en",
"#text": "Relay 1"
}
],
"bitSize": "8",
"unit": " %"
},
{
"offset": "36",
"name": [
"Relais 2",
{
"-lang": "en",
"#text": "Relay 2"
}
],
"bitSize": "8",
"unit": " %"
},
{
"offset": "37",
"name": [
"Relais 3",
{
"-lang": "en",
"#text": "Relay 3"
}
],
"bitSize": "8",
"unit": " %"
},
{
"offset": "38",
"name": [
"Relais 4",
{
"-lang": "en",
"#text": "Relay 4"
}
],
"bitSize": "8",
"unit": " %"
},
{
"offset": "39",
"name": [
"Relais 5",
{
"-lang": "en",
"#text": "Relay 5"
}
],
"bitSize": "8",
"unit": " %"
},
{
"offset": "40",
"name": [
"Ausgang 1",
{
"-lang": "en",
"#text": "Output 1"
}
],
"bitSize": "16",
"unit": " %"
},
{
"offset": "42",
"name": [
"Ausgang 2",
{
"-lang": "en",
"#text": "Output 2"
}
],
"bitSize": "16",
"unit": " %"
},
{
"offset": "44",
"name": [
"Ausgang 3",
{
"-lang": "en",
"#text": "Output 3"
}
],
"bitSize": "16",
"unit": " %"
},
{
"offset": "46",
"name": [
"Ausgang 4",
{
"-lang": "en",
"#text": "Output 4"
}
],
"bitSize": "16",
"unit": " %"
},
{
"offset": "50",
"name": [
"Lin Out",
{
"-lang": "en",
"#text": "Lin Out"
}
],
"bitSize": "16",
"factor": "0.1",
"unit": " %"
},
{
"offset": "60",
"name": [
"Fehler",
{
"-lang": "en",
"#text": "Error"
}
],
"bitSize": "16"
},
{
"offset": "60",
"name": ["Fehler S1"],
"bitSize": "1",
"bitPos": "1"
},
{
"offset": "60",
"name": ["Fehler S2"],
"bitSize": "1",
"bitPos": "2"
},
{
"offset": "60",
"name": ["Fehler S3"],
"bitSize": "1",
"bitPos": "3"
},
{
"offset": "60",
"name": ["Fehler S4"],
"bitSize": "1",
"bitPos": "4"
},
{
"offset": "60",
"name": ["Fehler S5"],
"bitSize": "1",
"bitPos": "5"
},
{
"offset": "60",
"name": ["Fehler S6"],
"bitSize": "1",
"bitPos": "6"
},
{
"offset": "60",
"name": ["Fehler S7"],
"bitSize": "1",
"bitPos": "7"
},
{
"offset": "60",
"name": ["Fehler S8"],
"bitSize": "1",
"bitPos": "8"
}
]
}
]
}
}
Hier noch der Docker Bauplan für das Image, basierend auf python-slim
die pyhton-scripts sind als persitenters Volume unter /app gemountet
Code: Alles auswählen
CMD ["bash"]
ENV PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV LANG=C.UTF-8
RUN set -eux; apt-get update; apt-get install -y --no-install-recommends ca-certificates netbase tzdata ; rm -rf /var/lib/apt/lists/*
ENV GPG_KEY=A035C8C19219BA821ECEA86B64E628F8D684696D
ENV PYTHON_VERSION=3.10.2
RUN set -eux; savedAptMark="$(apt-mark showmanual)"; apt-get update; apt-get install -y --no-install-recommends dpkg-dev gcc gnupg dirmngr libbluetooth-dev libbz2-dev libc6-dev libexpat1-dev libffi-dev libgdbm-dev liblzma-dev libncursesw5-dev libreadline-dev libsqlite3-dev libssl-dev make tk-dev uuid-dev wget xz-utils zlib1g-dev ; wget -O python.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz"; wget -O python.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc"; GNUPGHOME="$(mktemp -d)"; export GNUPGHOME; gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$GPG_KEY"; gpg --batch --verify python.tar.xz.asc python.tar.xz; command -v gpgconf > /dev/null && gpgconf --kill all || :; rm -rf "$GNUPGHOME" python.tar.xz.asc; mkdir -p /usr/src/python; tar --extract --directory /usr/src/python --strip-components=1 --file python.tar.xz; rm python.tar.xz; cd /usr/src/python; gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; ./configure --build="$gnuArch" --enable-loadable-sqlite-extensions --enable-optimizations --enable-option-checking=fatal --enable-shared --with-lto --with-system-expat --with-system-ffi --without-ensurepip ; nproc="$(nproc)"; make -j "$nproc" LDFLAGS="-Wl,--strip-all" ; make install; cd /; rm -rf /usr/src/python; find /usr/local -depth \( \( -type d -a \( -name test -o -name tests -o -name idle_test \) \) -o \( -type f -a \( -name '*.pyc' -o -name '*.pyo' -o -name '*.a' \) \) \) -exec rm -rf '{}' + ; ldconfig; apt-mark auto '.*' > /dev/null; apt-mark manual $savedAptMark; find /usr/local -type f -executable -not \( -name '*tkinter*' \) -exec ldd '{}' ';' | awk '/=>/ { print $(NF-1) }' | sort -u | xargs -r dpkg-query --search | cut -d: -f1 | sort -u | xargs -r apt-mark manual ; apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; rm -rf /var/lib/apt/lists/*; python3 --version
RUN set -eux; for src in idle3 pydoc3 python3 python3-config; do dst="$(echo "$src" | tr -d 3)"; [ -s "/usr/local/bin/$src" ]; [ ! -e "/usr/local/bin/$dst" ]; ln -svT "/usr/local/bin/$src" "/usr/local/bin/$dst"; done
ENV PYTHON_PIP_VERSION=21.2.4
ENV PYTHON_SETUPTOOLS_VERSION=58.1.0
ENV PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/2caf84b14febcda8077e59e9b8a6ef9a680aa392/public/get-pip.py
ENV PYTHON_GET_PIP_SHA256=7c5239cea323cadae36083079a5ee6b2b3d56f25762a0c060d2867b89e5e06c5
RUN set -eux; savedAptMark="$(apt-mark showmanual)"; apt-get update; apt-get install -y --no-install-recommends wget; wget -O get-pip.py "$PYTHON_GET_PIP_URL"; echo "$PYTHON_GET_PIP_SHA256 *get-pip.py" | sha256sum -c -; apt-mark auto '.*' > /dev/null; [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; rm -rf /var/lib/apt/lists/*; python get-pip.py --disable-pip-version-check --no-cache-dir "pip==$PYTHON_PIP_VERSION" "setuptools==$PYTHON_SETUPTOOLS_VERSION" ; pip --version; find /usr/local -depth \( \( -type d -a \( -name test -o -name tests -o -name idle_test \) \) -o \( -type f -a \( -name '*.pyc' -o -name '*.pyo' \) \) \) -exec rm -rf '{}' + ; rm -f get-pip.py
CMD ["python3"]
VOLUME [/app]
WORKDIR /app
RUN pip install pyserial paho-mqtt
ENTRYPOINT ["/bin/sh" "-c" "python3 /app/resol-vbus-python/resol3mqtt.py\"]"]
timberwolf714 (TWS3500) | VPN offen | Reboot tagsüber erlaubt
-
- Elaborated Networks
- Reactions:
- Beiträge: 10231
- Registriert: So Aug 12, 2018 9:27 am
- Wohnort: Frauenneuharting
- Hat sich bedankt: 5057 Mal
- Danksagung erhalten: 8221 Mal
- Kontaktdaten:
Hallo Moriz,
willkommen hier im Forum und dann gleich so ein Expertenbeitrag. Toll. ich bin begeistert.
ich hoffe mehr von Dir zu lesen.
lg
Stefan
willkommen hier im Forum und dann gleich so ein Expertenbeitrag. Toll. ich bin begeistert.
ich hoffe mehr von Dir zu lesen.
lg
Stefan
Stefan Werner
Product Owner für Timberwolf Server, 1-Wire und BlitzART
Bitte WIKI lesen. Allg. Support nur im Forum. Bitte keine PN
Zu Preisen, Lizenzen, Garantie, HW-Defekt an service at elabnet dot de
Link zu Impressum und Datenschutzerklärung oben.
Product Owner für Timberwolf Server, 1-Wire und BlitzART
Bitte WIKI lesen. Allg. Support nur im Forum. Bitte keine PN
Zu Preisen, Lizenzen, Garantie, HW-Defekt an service at elabnet dot de
Link zu Impressum und Datenschutzerklärung oben.
-
- Reactions:
- Beiträge: 530
- Registriert: Mo Dez 02, 2019 5:38 am
- Wohnort: Freital
- Hat sich bedankt: 418 Mal
- Danksagung erhalten: 230 Mal
Vielen Dank Moriz
Werde mir das bei Gelegenheit mal ansehen.
Welche Werte bekommst du aus der Frischwasserstation?
Kannst du diese auch steuern zB Zirkulationspumpe An/Aus?
Werde mir das bei Gelegenheit mal ansehen.
Welche Werte bekommst du aus der Frischwasserstation?
Kannst du diese auch steuern zB Zirkulationspumpe An/Aus?
Grüße Micha
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
-
- Reactions:
- Beiträge: 530
- Registriert: Mo Dez 02, 2019 5:38 am
- Wohnort: Freital
- Hat sich bedankt: 418 Mal
- Danksagung erhalten: 230 Mal
Kannst du mir dein Docker Container zur Verfügung stellen? Dann muss ich den nur noch auf Viessmann anpassen.
Ich muss bei mir wahrscheinlich einen VBus zu LAN Adapter verwenden da die Heizung zuweist vom TWS entfernt ist.
Ich muss bei mir wahrscheinlich einen VBus zu LAN Adapter verwenden da die Heizung zuweist vom TWS entfernt ist.
Grüße Micha
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
Leider habe ich auf die Schnelle die Export-Funktion in Portainer nicht gefunden. @StefanW: Gibt es einen Weg, den Container oder das Image aus dem Timberwolf zu exportieren?
Aktuell habe ich bisher nur Lesen implementiert. Ich lesen folgende Werte (wie in Regumaq-X45.json definiert):
- Alle Temperaturen (S1 - S8),
bei mir: Speichertemperatur Oben, Mitte, Unten, Speichervorlauf, Speicherrücklauf, Kaltwassertemperatur, Warmwassertemperatur
- Schaltzustände der Ausgangsrelais (R1-R5),
bei mir: Ladepumpe an, Zirkulation an, Anforderung Zonenladung an WP, Motorkugelhahn Rücklaufeinschichtung
- Fehlermeldungen der Sensoren
- PWM-Ausgangszustände,
bei mir: Drehzahl der Ladepumpe
- Volumenstrom Warmwasser
Zusätzlich wären noch die Systemzeit und die Infos zur thermischen Desinfektion verfügbar, die habe ich bei mir allerdings nicht implementiert, da nicht genutzt.
Laut der Doku von Resol sind für meine Station keine Schreibbefehle vorgesehen. Die Zirkulationspumpe steuere ich über einen KNX-Ausgang an, der auf den Sensor-Eingang der Frischwasserstation für Zirkulationsanforderung wirkt. (Lässt sich im Controller der Frischwasserstation so konfigurieren).
Wenn ich nochmal kaufen würde, würde ich auch das zusätzliche Geld für den VBUS Lan Adapter investieren. Die USB-Verbindung über den Timberwolf in den Docker-Container läuft bei mir nicht immer stabil, sodass gelegentlich ein Neustart des TWS nötig ist, damit das USB-Gerät wieder im Portainer verfügbar ist.
Aktuell habe ich bisher nur Lesen implementiert. Ich lesen folgende Werte (wie in Regumaq-X45.json definiert):
- Alle Temperaturen (S1 - S8),
bei mir: Speichertemperatur Oben, Mitte, Unten, Speichervorlauf, Speicherrücklauf, Kaltwassertemperatur, Warmwassertemperatur
- Schaltzustände der Ausgangsrelais (R1-R5),
bei mir: Ladepumpe an, Zirkulation an, Anforderung Zonenladung an WP, Motorkugelhahn Rücklaufeinschichtung
- Fehlermeldungen der Sensoren
- PWM-Ausgangszustände,
bei mir: Drehzahl der Ladepumpe
- Volumenstrom Warmwasser
Zusätzlich wären noch die Systemzeit und die Infos zur thermischen Desinfektion verfügbar, die habe ich bei mir allerdings nicht implementiert, da nicht genutzt.
Laut der Doku von Resol sind für meine Station keine Schreibbefehle vorgesehen. Die Zirkulationspumpe steuere ich über einen KNX-Ausgang an, der auf den Sensor-Eingang der Frischwasserstation für Zirkulationsanforderung wirkt. (Lässt sich im Controller der Frischwasserstation so konfigurieren).
Wenn ich nochmal kaufen würde, würde ich auch das zusätzliche Geld für den VBUS Lan Adapter investieren. Die USB-Verbindung über den Timberwolf in den Docker-Container läuft bei mir nicht immer stabil, sodass gelegentlich ein Neustart des TWS nötig ist, damit das USB-Gerät wieder im Portainer verfügbar ist.
timberwolf714 (TWS3500) | VPN offen | Reboot tagsüber erlaubt
-
- Reactions:
- Beiträge: 2191
- Registriert: So Aug 12, 2018 1:38 pm
- Wohnort: Karlsruher Raum
- Hat sich bedankt: 485 Mal
- Danksagung erhalten: 897 Mal
Hi Micha @Mibr85 ,
ist das Thema bei Dir noch aktuell? Ich hab die letzten Tage auch an meiner Heizung rumgebastelt, bin aber über die Optolink-Schnittstelle gegangen.
ist das Thema bei Dir noch aktuell? Ich hab die letzten Tage auch an meiner Heizung rumgebastelt, bin aber über die Optolink-Schnittstelle gegangen.
Lg
Jochen
____________________________________________________________
TW 2600 #188
VPN offen, Zugriff jederzeit, Experimente jederzeit, Reboot jederzeit
Jochen
____________________________________________________________
TW 2600 #188
VPN offen, Zugriff jederzeit, Experimente jederzeit, Reboot jederzeit
-
- Reactions:
- Beiträge: 530
- Registriert: Mo Dez 02, 2019 5:38 am
- Wohnort: Freital
- Hat sich bedankt: 418 Mal
- Danksagung erhalten: 230 Mal
Hallo Jochen
Ja das Thema ist noch aktuell und wird es immer mehr da Viessmann die API immer weiter beschneidet ä z.B. einige Temperaturen in 1K Auflösung statt 0,1K. Das macht die API für zB Warmwassersteuerung unbrauchbar.
Leider hatte ich noch keine Zeit mich damit weiter zu beschäftigen.
Wie hast du es denn gelöst?
Ja das Thema ist noch aktuell und wird es immer mehr da Viessmann die API immer weiter beschneidet ä z.B. einige Temperaturen in 1K Auflösung statt 0,1K. Das macht die API für zB Warmwassersteuerung unbrauchbar.
Leider hatte ich noch keine Zeit mich damit weiter zu beschäftigen.
Wie hast du es denn gelöst?
Grüße Micha
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
TWS 3500 XL #1209 + TWS 2600 #528 + PBM #972,
VPN offen, Reboot möglich
PLZ 01...
-
- Reactions:
- Beiträge: 395
- Registriert: Mi Sep 12, 2018 1:11 am
- Wohnort: NRW
- Hat sich bedankt: 212 Mal
- Danksagung erhalten: 253 Mal
für meine Anlage habe ich das Gegenteil - nach Inbetriebnahme in 09/2022 habe ich kürzlich noch weitere Datenpunkte hinzubekommen.da Viessmann die API immer weiter beschneidet ä z.B. einige Temperaturen in 1K Auflösung statt 0,1K
Bei mir werden auch alle Temperaturen mit 0,1K aufgelöst.
Langfristig reizt mich der VBus aber auch
VG Alex
Timberwolf122 (TWS 2500) // Wartungs-VPN: offen // Reboot: jederzeit
Timberwolf122 (TWS 2500) // Wartungs-VPN: offen // Reboot: jederzeit