Initial commit
This commit is contained in:
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
.mypy_cache/
|
||||
|
||||
# local files
|
||||
.env
|
||||
.vscode
|
||||
1
__init__.py
Normal file
1
__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__version__ = "0.1.0"
|
||||
60
device_dsmr.py
Normal file
60
device_dsmr.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from homie.device_base import Device_Base
|
||||
from homie.node.node_base import Node_Base
|
||||
|
||||
|
||||
|
||||
from settings import Settings
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SETTINGS = Settings()
|
||||
|
||||
TRANSLATED_MQTT_SETTINGS = {
|
||||
'MQTT_BROKER': SETTINGS.mqtt_host,
|
||||
'MQTT_PORT': SETTINGS.mqtt_port,
|
||||
'MQTT_USERNAME' : SETTINGS.mqtt_username,
|
||||
'MQTT_PASSWORD' : SETTINGS.mqtt_password,
|
||||
'MQTT_CLIENT_ID' : SETTINGS.hostname,
|
||||
'MQTT_SHARE_CLIENT': False,
|
||||
}
|
||||
|
||||
TRANSLATED_HOMIE_SETTINGS = {
|
||||
'topic' : SETTINGS.homie_topic,
|
||||
'fw_name' : SETTINGS.homie_fw_name,
|
||||
'fw_version' : SETTINGS.homie_fw_version,
|
||||
'update_interval' : SETTINGS.homie_update_interval,
|
||||
}
|
||||
|
||||
class Device_DSMR(Device_Base):
|
||||
def __init__(self, device_id=None, name=None, homie_settings=TRANSLATED_HOMIE_SETTINSG, mqtt_settings=TRANSLATED_MQTT_SETTINGS):
|
||||
|
||||
super().__init__(device_id, name, homie_settings, mqtt_settings)
|
||||
|
||||
node = Node_Base(self, "gasmeter", "Gasmeter", "status")
|
||||
self.add_node(node)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
self.start()
|
||||
|
||||
|
||||
def register_status_properties(self, node):
|
||||
super(Device_Temperature_Humidity_Battery, self).register_status_properties(
|
||||
node
|
||||
)
|
||||
|
||||
self.battery = Property_Battery(node)
|
||||
node.add_property(self.battery)
|
||||
|
||||
def update_battery(self, battery):
|
||||
logger.info("Updated Battery {}".format(battery))
|
||||
self.battery.value = battery
|
||||
|
||||
|
||||
|
||||
/Ene5\T210-D ESMR5.0
|
||||
|
||||
134
dsmr2mqtt.py
Normal file
134
dsmr2mqtt.py
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python
|
||||
# Python script om P1 telegram weer te geven
|
||||
|
||||
import datetime
|
||||
import re
|
||||
import serial
|
||||
import homie
|
||||
import paho.mqtt.client as paho
|
||||
|
||||
VERSION = 0.1
|
||||
|
||||
|
||||
|
||||
def on_publish(client,userdata,result): #create function for callback
|
||||
print("data published \n")
|
||||
pass
|
||||
|
||||
client1=paho.Client("control1") #create client object
|
||||
client1.on_publish = on_publish #assign function to callback
|
||||
client1.connect(broker,port) #establish connection
|
||||
|
||||
|
||||
class DSMRConnection:
|
||||
def __init__(self):
|
||||
"""Seriele poort confguratie naar DSMR configuratie"""
|
||||
cfg = Settings()
|
||||
self.serial = serial.Serial(
|
||||
port=cfg.dsmr_port,
|
||||
baudrate=cfg.dsmr_baudrate,
|
||||
parity=serial.PARITY_NAMES[cfg.dsmr_parity],
|
||||
timeout=10,
|
||||
xonxoff=0
|
||||
)
|
||||
|
||||
self.mqttclient = paho.Client(cfg.)
|
||||
|
||||
kwhtot = 0
|
||||
kwhoud = 0
|
||||
kwhverschil = 0
|
||||
|
||||
gastot = 0
|
||||
gasoud = 0
|
||||
gasverschil = 0
|
||||
|
||||
# Telegram
|
||||
#
|
||||
# /KMP5 KA6U001660740912
|
||||
#
|
||||
# 0-0:96.1.1(204B413655303031363630373430393132)
|
||||
# 1-0:1.8.1(13629.373*kWh)
|
||||
# 1-0:1.8.2(14700.866*kWh)
|
||||
# 1-0:2.8.1(00000.000*kWh)
|
||||
# 1-0:2.8.2(00000.000*kWh)
|
||||
# 0-0:96.14.0(0001)
|
||||
# 1-0:1.7.0(0000.64*kW)
|
||||
# 1-0:2.7.0(0000.00*kW)
|
||||
# 0-0:96.13.1()
|
||||
# 0-0:96.13.0()
|
||||
# 0-1:24.1.0(3)
|
||||
# 0-1:96.1.0(3238313031353431303037343732343132)
|
||||
# 0-1:24.3.0(180428140000)(08)(60)(1)(0-1:24.2.1)(m3)
|
||||
# (03862.650)
|
||||
# !
|
||||
|
||||
while True:
|
||||
ser.open()
|
||||
checksum_found = False
|
||||
gasflag = 0
|
||||
|
||||
while not checksum_found:
|
||||
telegram_line = ser.readline() # Lees een seriele lijn in.
|
||||
telegram_line = telegram_line.decode('ascii').strip() # Strip spaties en blanke regels
|
||||
|
||||
#print (telegram_line) #debug
|
||||
|
||||
if re.match(b'(?=1-0:1.7.0)', telegram_line): #1-0:1.7.0 = Actueel verbruik in kW
|
||||
# 1-0:1.7.0(0000.54*kW)
|
||||
kw = telegram_line[10:-4] # Knip het kW gedeelte eruit (0000.54)
|
||||
watt = float(kw) * 1000 # vermengvuldig met 1000 voor conversie naar Watt (540.0)
|
||||
watt = int(watt) # rond float af naar heel getal (540)
|
||||
|
||||
if re.match(b'(?=1-0:1.8.1)', telegram_line): #1-0:1.8.1 - Hoog tarief / 1-0:1.8.1(13579.595*kWh)
|
||||
kwh1 = telegram_line[10:-5] # Knip het kWh gedeelte eruit (13579.595)
|
||||
|
||||
if re.match(b'(?=1-0:1.8.2)', telegram_line): #1-0:1.8.2 - Laag tarief / 1-0:1.8.2(14655.223*kWh)
|
||||
kwh2 = telegram_line[10:-5] # Knip het kWh gedeelte eruit (14655.223)
|
||||
|
||||
if gasflag == 1:
|
||||
gas = telegram_line[1:-1]
|
||||
gasflag = 0
|
||||
|
||||
if re.match(b'(?=0-1:24.3.0)', telegram_line): #0-1:24.3.0 - Gasverbruik
|
||||
gasflag = 1
|
||||
|
||||
# Check wanneer het uitroepteken ontavangen wordt (einde telegram)
|
||||
if re.match(b'(?=!)', telegram_line):
|
||||
checksum_found = True
|
||||
|
||||
ser.close()
|
||||
|
||||
#######################################
|
||||
if kwhoud < 1: #Script eerste keer opgestart, sla waarde op
|
||||
kwhoud = kwhtot
|
||||
|
||||
kwhtot = float(kwh1) + float(kwh2)
|
||||
kwhverschil = round(float(kwhtot) - float(kwhoud), 3)
|
||||
|
||||
if gasoud < 1: #Script eerste keer opgestart, sla waarde op
|
||||
gasoud = gas
|
||||
gasouduur = gas
|
||||
|
||||
gasverschil = round(float(gas) - float(gasoud), 3)
|
||||
gasverschiluur = round(float(gas) - float(gasouduur), 3)
|
||||
|
||||
# Reset tellers
|
||||
|
||||
tijd = str(datetime.datetime.now().time())[0:-10]
|
||||
tijdmin = str(datetime.datetime.now().time())[3:-10]
|
||||
|
||||
if tijd == "00:00": # Reset de counter van de dag
|
||||
kwhoud = kwhtot
|
||||
gasoud = gas
|
||||
|
||||
if tijdmin == "00": # Reset de counter van het uur
|
||||
gasouduur = gas
|
||||
|
||||
######################################
|
||||
# MQTT PUBLISH
|
||||
######################################
|
||||
|
||||
client1.publish("elektra\w", watt)
|
||||
client1.publish("elektra\kwh", kwhverschil)
|
||||
client1.publish("gas", gasverschil)
|
||||
client1.publish("gas\\uur", gasverschiluur)
|
||||
0
node/__init__.py
Normal file
0
node/__init__.py
Normal file
85
node/node_electricitymeter.py
Normal file
85
node/node_electricitymeter.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from homie.node.node_base import Node_Base
|
||||
|
||||
from homie.node.property.property_enum import Property_Enum
|
||||
from homie.node.property.property_integer import Property_Integer
|
||||
from dsmr2mqtt.node.property.property_energy import Property_Energy
|
||||
from dsmr2mqtt.node.property.property_power import Property_Power
|
||||
from dsmr2mqtt.node.property.property_current import Property_Current
|
||||
from dsmr2mqtt.node.property.property_voltage import Property_Voltage
|
||||
|
||||
|
||||
class Node_ElectricityMeter(Node_Base):
|
||||
def __init__(
|
||||
self,
|
||||
device,
|
||||
id="electricitymeter",
|
||||
name="Electricity meter",
|
||||
type_="state",
|
||||
retain=True,
|
||||
qos=1,
|
||||
state_values=None,
|
||||
set_state=None,
|
||||
):
|
||||
assert state_values
|
||||
assert set_state
|
||||
|
||||
super().__init__(device, id, name, type_, retain, qos)
|
||||
|
||||
|
||||
self.add_property(Property_Integer(self, "tariff_indicator", "Tariff indicator", data_format="1:2", settable=False))
|
||||
|
||||
self.add_property(Property_Energy(self, "delivery_tariff1", "Delivery tariff 1"))
|
||||
self.add_property(Property_Energy(self, "delivery_tariff2", "Delivery tariff 2"))
|
||||
self.add_property(Property_Power(self, "power", "Power"))
|
||||
|
||||
self.add_property(Property_Voltage(self, "voltage_L1", "Voltage L1"))
|
||||
self.add_property(Property_Voltage(self, "voltage_L2", "Voltage L2"))
|
||||
self.add_property(Property_Voltage(self, "voltage_L3", "Voltage L3"))
|
||||
|
||||
self.add_property(Property_Current(self, "current_L1", "Current L1"))
|
||||
self.add_property(Property_Current(self, "current_L2", "Current L2"))
|
||||
self.add_property(Property_Current(self, "current_L3", "Current L3"))
|
||||
|
||||
self.add_property(Property_Power(self, "power_L1", "Power L1"))
|
||||
self.add_property(Property_Power(self, "power_L2", "Power L2"))
|
||||
self.add_property(Property_Power(self, "power_L3", "Power L3"))
|
||||
|
||||
def update_status(self, telegram: str):
|
||||
|
||||
#Telegram
|
||||
# 1-3:0.2.8(50)
|
||||
# 0-0:1.0.0(200603122725S)
|
||||
# 0-0:96.1.1(4530303438303030303339393038333139)
|
||||
# 1-0:1.8.1(001807.864*kWh)
|
||||
# 1-0:1.8.2(001173.872*kWh)
|
||||
# 1-0:2.8.1(000000.091*kWh)
|
||||
# 1-0:2.8.2(000000.000*kWh)
|
||||
# 0-0:96.14.0(0002)
|
||||
# 1-0:1.7.0(00.909*kW)
|
||||
# 1-0:2.7.0(00.000*kW)
|
||||
# 0-0:96.7.21(00016)
|
||||
# 0-0:96.7.9(00003)
|
||||
# 1-0:99.97.0(0)(0-0:96.7.19)
|
||||
# 1-0:32.32.0(00002)
|
||||
# 1-0:52.32.0(00002)
|
||||
# 1-0:72.32.0(00002)
|
||||
# 1-0:32.36.0(00000)
|
||||
# 1-0:52.36.0(00000)
|
||||
# 1-0:72.36.0(00000)
|
||||
# 0-0:96.13.0()
|
||||
# 1-0:32.7.0(235.0*V)
|
||||
# 1-0:52.7.0(237.0*V)
|
||||
# 1-0:72.7.0(236.0*V)
|
||||
# 1-0:31.7.0(001*A)
|
||||
# 1-0:51.7.0(001*A)
|
||||
# 1-0:71.7.0(001*A)
|
||||
# 1-0:21.7.0(00.290*kW)
|
||||
# 1-0:41.7.0(00.268*kW)
|
||||
# 1-0:61.7.0(00.350*kW)
|
||||
# 1-0:22.7.0(00.000*kW)
|
||||
# 1-0:42.7.0(00.000*kW)
|
||||
# 1-0:62.7.0(00.000*kW)
|
||||
# 0-1:24.1.0(003)
|
||||
# 0-1:96.1.0(4730303732303033393435373234323139)
|
||||
# 0-1:24.2.1(200603122500S)(01741.782*m3)
|
||||
pass
|
||||
31
node/node_gasmeter.py
Normal file
31
node/node_gasmeter.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from homie.node.node_base import Node_Base
|
||||
|
||||
from homie.node.property.property_enum import Property_Enum
|
||||
from dsmr2mqtt.node.property.property_volume import Property_Volume
|
||||
|
||||
|
||||
class Node_Gasmeter(Node_Base):
|
||||
def __init__(
|
||||
self,
|
||||
device,
|
||||
id="gasmeter",
|
||||
name="Gas meter",
|
||||
type_="state",
|
||||
retain=True,
|
||||
qos=1,
|
||||
state_values=None,
|
||||
set_state=None,
|
||||
):
|
||||
assert state_values
|
||||
assert set_state
|
||||
|
||||
super().__init__(device, id, name, type_, retain, qos)
|
||||
|
||||
self.add_property(
|
||||
Property_Volume(
|
||||
self, "volume", "Volume", data_format=state_values, set_value=set_state
|
||||
)
|
||||
)
|
||||
|
||||
def update_volume(self, volume):
|
||||
self.get_property("volume").value = volume
|
||||
0
node/property/__init__.py
Normal file
0
node/property/__init__.py
Normal file
37
node/property/property_current.py
Normal file
37
node/property/property_current.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from homie.node.property.property_float import Property_Float
|
||||
|
||||
|
||||
class Property_Current(Property_Float):
|
||||
def __init__(
|
||||
self,
|
||||
node,
|
||||
id="current",
|
||||
name="Current",
|
||||
settable=False,
|
||||
retained=True,
|
||||
qos=1,
|
||||
unit="A",
|
||||
data_type=None,
|
||||
data_format=None,
|
||||
value=None,
|
||||
set_value=None,
|
||||
tags=[],
|
||||
meta={},
|
||||
):
|
||||
|
||||
super().__init__(
|
||||
node,
|
||||
id,
|
||||
name,
|
||||
settable,
|
||||
retained,
|
||||
qos,
|
||||
unit,
|
||||
data_type,
|
||||
data_format,
|
||||
value,
|
||||
set_value,
|
||||
tags,
|
||||
meta,
|
||||
)
|
||||
|
||||
37
node/property/property_energy.py
Normal file
37
node/property/property_energy.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from homie.node.property.property_float import Property_Float
|
||||
|
||||
|
||||
class Property_Energy(Property_Float):
|
||||
def __init__(
|
||||
self,
|
||||
node,
|
||||
id="energy",
|
||||
name="Energy",
|
||||
settable=False,
|
||||
retained=True,
|
||||
qos=1,
|
||||
unit="kWh",
|
||||
data_type=None,
|
||||
data_format=None,
|
||||
value=None,
|
||||
set_value=None,
|
||||
tags=[],
|
||||
meta={},
|
||||
):
|
||||
|
||||
super().__init__(
|
||||
node,
|
||||
id,
|
||||
name,
|
||||
settable,
|
||||
retained,
|
||||
qos,
|
||||
unit,
|
||||
data_type,
|
||||
data_format,
|
||||
value,
|
||||
set_value,
|
||||
tags,
|
||||
meta,
|
||||
)
|
||||
|
||||
37
node/property/property_power.py
Normal file
37
node/property/property_power.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from homie.node.property.property_float import Property_Float
|
||||
|
||||
|
||||
class Property_Power(Property_Float):
|
||||
def __init__(
|
||||
self,
|
||||
node,
|
||||
id="power",
|
||||
name="Power",
|
||||
settable=False,
|
||||
retained=True,
|
||||
qos=1,
|
||||
unit="W",
|
||||
data_type=None,
|
||||
data_format=None,
|
||||
value=None,
|
||||
set_value=None,
|
||||
tags=[],
|
||||
meta={},
|
||||
):
|
||||
|
||||
super().__init__(
|
||||
node,
|
||||
id,
|
||||
name,
|
||||
settable,
|
||||
retained,
|
||||
qos,
|
||||
unit,
|
||||
data_type,
|
||||
data_format,
|
||||
value,
|
||||
set_value,
|
||||
tags,
|
||||
meta,
|
||||
)
|
||||
|
||||
37
node/property/property_voltage.py
Normal file
37
node/property/property_voltage.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from homie.node.property.property_float import Property_Float
|
||||
|
||||
|
||||
class Property_Voltage(Property_Float):
|
||||
def __init__(
|
||||
self,
|
||||
node,
|
||||
id="voltage",
|
||||
name="Voltage",
|
||||
settable=False,
|
||||
retained=True,
|
||||
qos=1,
|
||||
unit="V",
|
||||
data_type=None,
|
||||
data_format=None,
|
||||
value=None,
|
||||
set_value=None,
|
||||
tags=[],
|
||||
meta={},
|
||||
):
|
||||
|
||||
super().__init__(
|
||||
node,
|
||||
id,
|
||||
name,
|
||||
settable,
|
||||
retained,
|
||||
qos,
|
||||
unit,
|
||||
data_type,
|
||||
data_format,
|
||||
value,
|
||||
set_value,
|
||||
tags,
|
||||
meta,
|
||||
)
|
||||
|
||||
37
node/property/property_volume.py
Normal file
37
node/property/property_volume.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from homie.node.property.property_float import Property_Float
|
||||
|
||||
|
||||
class Property_Volume(Property_Float):
|
||||
def __init__(
|
||||
self,
|
||||
node,
|
||||
id="volume",
|
||||
name="Volume",
|
||||
settable=False,
|
||||
retained=True,
|
||||
qos=1,
|
||||
unit="m³",
|
||||
data_type=None,
|
||||
data_format=None,
|
||||
value=None,
|
||||
set_value=None,
|
||||
tags=[],
|
||||
meta={},
|
||||
):
|
||||
|
||||
super().__init__(
|
||||
node,
|
||||
id,
|
||||
name,
|
||||
settable,
|
||||
retained,
|
||||
qos,
|
||||
unit,
|
||||
data_type,
|
||||
data_format,
|
||||
value,
|
||||
set_value,
|
||||
tags,
|
||||
meta,
|
||||
)
|
||||
|
||||
31
settings.py
Normal file
31
settings.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from pydantic import BaseSettings, Field
|
||||
|
||||
from openhab.__init__ import __version__
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Application settings for the DSMR MQTT bridge."""
|
||||
|
||||
loglevel: str = Field('INFO', env='LOGLEVEL')
|
||||
|
||||
mqtt_host: str = Field(None, env='MQTT_HOST')
|
||||
mqtt_port: int = Field(1883, env='MQTT_PORT')
|
||||
mqtt_username: str = Field(None, env='MQTT_USERNAME')
|
||||
mqtt_password: str = Field(None, env='MQTT_PASSWORD')
|
||||
|
||||
dsmr_port: str = Field('/dev/ttyUSB0', env='DSMR_PORT')
|
||||
dsmr_baudrate: str = Field(115200, env='DSMR_BAUDRATE')
|
||||
dsmr_bytesize: str = Field('EIGHTBITS', env='DSMR_BITESIZE')
|
||||
dsmr_parity: str = Field('NONE', env='DSMR_PARITY')
|
||||
dsmr_stopbits: str = Field('ONE', env='DSMR_STOPBITS')
|
||||
|
||||
homie_update_interval: int = 60
|
||||
homie_topic: str = Field('homie', env='HOMIE_TOPIC')
|
||||
homie_implementation: str \
|
||||
= f"DSMR Homie {VERSION} Homie 4 Version {homie.__version__}"
|
||||
homie_fw_name: str = "DSMR"
|
||||
homie_fw_version: str = "0.1.0"
|
||||
|
||||
class Config:
|
||||
"""Where to find the environment file containing the settings."""
|
||||
env_file = '.env'
|
||||
Reference in New Issue
Block a user