Initial revision of fronius2mqtt
This commit is contained in:
commit
76cc7371b1
16 changed files with 331 additions and 0 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
__pycache__
|
||||
bin
|
||||
lib
|
||||
fronius2mqtt.bbprojectd
|
||||
pip-selfcheck.json
|
||||
pyvenv.cfg
|
||||
fronius2mqtt/fronius2mqtt.egg-info
|
||||
fronius2mqtt.yaml
|
13
bin/start.py
Executable file
13
bin/start.py
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from fronius2mqtt import config
|
||||
from fronius2mqtt import daemon
|
||||
|
||||
def main():
|
||||
cfg = config.Config()
|
||||
cfg.read()
|
||||
d = daemon.Daemon(cfg)
|
||||
d.run()
|
||||
|
||||
main()
|
||||
|
26
fronius2mqtt.yaml.example
Normal file
26
fronius2mqtt.yaml.example
Normal file
|
@ -0,0 +1,26 @@
|
|||
mqtt:
|
||||
host: localhost
|
||||
port: 1883
|
||||
user: user
|
||||
password: secret
|
||||
topic: "mqtt/topic/for/fronius"
|
||||
fronius:
|
||||
- inverter:
|
||||
host: "inverter.myfroniusfarm"
|
||||
device: 1
|
||||
topic: "inverter_1"
|
||||
- inverter:
|
||||
host: "inverter.myfroniusfarm"
|
||||
device: 2
|
||||
topic: "inverter_2"
|
||||
- storage:
|
||||
host: "storage.myfroniusfarm"
|
||||
device: 0
|
||||
topic: "battery_1"
|
||||
- meter:
|
||||
host: "storage.myfroniusfarm"
|
||||
device: 0
|
||||
topic: "meter"
|
||||
- flow:
|
||||
host: "storage.myfroniusfarm"
|
||||
topic: "flow"
|
0
fronius2mqtt/fronius2mqtt/__init__.py
Normal file
0
fronius2mqtt/fronius2mqtt/__init__.py
Normal file
59
fronius2mqtt/fronius2mqtt/config.py
Normal file
59
fronius2mqtt/fronius2mqtt/config.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
import yaml
|
||||
import logging
|
||||
import logging.config
|
||||
|
||||
class Config:
|
||||
"""Class for parsing fronius2mqtt.yaml."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize Config class."""
|
||||
logging.config.fileConfig('logging.conf')
|
||||
self._mqtt = {}
|
||||
self._fronius = {}
|
||||
|
||||
|
||||
def read(self, file='fronius2mqtt.yaml'):
|
||||
"""Read config."""
|
||||
logging.debug("Reading %s", file)
|
||||
try:
|
||||
with open(file, 'r') as filehandle:
|
||||
config = yaml.load(filehandle)
|
||||
self._parse_mqtt(config)
|
||||
self._parse_fronius(config)
|
||||
except FileNotFoundError as ex:
|
||||
logging.error("Error while reading %s: %s", file, ex)
|
||||
|
||||
def _parse_mqtt(self, config):
|
||||
"""Parse the mqtt section of fronius2mqtt.yaml."""
|
||||
if "mqtt" in config:
|
||||
self._mqtt = config["mqtt"]
|
||||
if not "host" in self._mqtt:
|
||||
raise ValueError("MQTT host not set")
|
||||
if not "port" in self._mqtt:
|
||||
raise ValueError("MQTT port not set")
|
||||
if not "user" in self._mqtt:
|
||||
raise ValueError("MQTT user not set")
|
||||
if not "password" in self._mqtt:
|
||||
raise ValueError("MQTT password not set")
|
||||
if not "topic" in self._mqtt:
|
||||
raise ValueError("MQTT topic not set")
|
||||
|
||||
|
||||
def _parse_fronius(self, config):
|
||||
"""Parse the fronius section of fronius2mqtt.yaml."""
|
||||
if "fronius" in config:
|
||||
self._fronius = config["fronius"]
|
||||
for item in self._fronius:
|
||||
if len(item) != 1:
|
||||
raise ValueError("Fronius device configuration contains more than one item.")
|
||||
for (type, properties) in item.items():
|
||||
if not "host" in properties:
|
||||
raise ValueError("Missing host for Fronius device")
|
||||
if not "topic" in properties:
|
||||
raise ValueError("Missing topic for Fronius device")
|
||||
|
||||
def mqtt(self):
|
||||
return self._mqtt
|
||||
|
||||
def fronius(self):
|
||||
return self._fronius
|
27
fronius2mqtt/fronius2mqtt/daemon.py
Normal file
27
fronius2mqtt/fronius2mqtt/daemon.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
import time
|
||||
|
||||
from fronius2mqtt import froniusfactory
|
||||
from fronius2mqtt import mqtt
|
||||
|
||||
class Daemon:
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.devices = []
|
||||
self._init_mqtt()
|
||||
self._init_fronius()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
for device in self.devices:
|
||||
device.update_and_publish(self.mqtt)
|
||||
time.sleep(5)
|
||||
|
||||
def _init_mqtt(self):
|
||||
self.mqtt = mqtt.Mqtt(self.config.mqtt())
|
||||
self.mqtt.connect()
|
||||
|
||||
def _init_fronius(self):
|
||||
factory = froniusfactory.FroniusFactory(self.config.fronius())
|
||||
self.devices = factory.create_devices()
|
16
fronius2mqtt/fronius2mqtt/device.py
Normal file
16
fronius2mqtt/fronius2mqtt/device.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
import logging
|
||||
|
||||
class Device:
|
||||
|
||||
def update(self):
|
||||
raise NotImplementedError("update not implemented")
|
||||
|
||||
def update_and_publish(self, mqtt):
|
||||
data = self.update()
|
||||
for (key, value) in data.items():
|
||||
if 'value' in value:
|
||||
mqtt.publish("{}/{}".format(self.topic, key), value['value'])
|
||||
else:
|
||||
logging.info("Ignore %s: %s", key, value)
|
||||
|
14
fronius2mqtt/fronius2mqtt/flow.py
Normal file
14
fronius2mqtt/fronius2mqtt/flow.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
from pyfronius import fronius
|
||||
from fronius2mqtt import device
|
||||
|
||||
class Flow(device.Device):
|
||||
|
||||
def __init__(self, config):
|
||||
self.host = config['host']
|
||||
self.topic = config['topic']
|
||||
self.fronius = fronius.Fronius(self.host)
|
||||
|
||||
def update(self):
|
||||
data = self.fronius.current_power_flow()
|
||||
return data
|
43
fronius2mqtt/fronius2mqtt/froniusfactory.py
Normal file
43
fronius2mqtt/fronius2mqtt/froniusfactory.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
from fronius2mqtt import inverter
|
||||
from fronius2mqtt import storage
|
||||
from fronius2mqtt import flow
|
||||
from fronius2mqtt import meter
|
||||
|
||||
class FroniusFactory:
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
def create_devices(self):
|
||||
devices = []
|
||||
for c in self.config:
|
||||
(type, properties) = c.popitem()
|
||||
if not type in factory:
|
||||
raise ValueError("Not a valid device: {}".format(type))
|
||||
device = factory[type](properties)
|
||||
devices.append(device)
|
||||
return devices
|
||||
|
||||
def _create_inverter(properties):
|
||||
device = inverter.Inverter(properties)
|
||||
return device
|
||||
|
||||
def _create_storage(properties):
|
||||
device = storage.Storage(properties)
|
||||
return device
|
||||
|
||||
def _create_meter(properties):
|
||||
device = meter.Meter(properties)
|
||||
return device
|
||||
|
||||
def _create_flow(properties):
|
||||
device = flow.Flow(properties)
|
||||
return device
|
||||
|
||||
factory = {
|
||||
"inverter" : _create_inverter,
|
||||
"storage" : _create_storage,
|
||||
"meter" : _create_meter,
|
||||
"flow" : _create_flow
|
||||
}
|
19
fronius2mqtt/fronius2mqtt/inverter.py
Normal file
19
fronius2mqtt/fronius2mqtt/inverter.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
from pyfronius import fronius
|
||||
from fronius2mqtt import device
|
||||
|
||||
class Inverter(device.Device):
|
||||
|
||||
def __init__(self, config):
|
||||
self.host = config['host']
|
||||
if 'device' in config:
|
||||
self.device = config['device']
|
||||
self.topic = config['topic']
|
||||
self.fronius = fronius.Fronius(self.host)
|
||||
|
||||
def update(self):
|
||||
if hasattr(self, 'device'):
|
||||
data = self.fronius.current_inverter_data(self.device)
|
||||
else:
|
||||
data = self.fronius.current_system_inverter_data()
|
||||
return data
|
19
fronius2mqtt/fronius2mqtt/meter.py
Normal file
19
fronius2mqtt/fronius2mqtt/meter.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
from pyfronius import fronius
|
||||
from fronius2mqtt import device
|
||||
|
||||
class Meter(device.Device):
|
||||
|
||||
def __init__(self, config):
|
||||
self.host = config['host']
|
||||
if 'device' in config:
|
||||
self.device = config['device']
|
||||
self.topic = config['topic']
|
||||
self.fronius = fronius.Fronius(self.host)
|
||||
|
||||
def update(self):
|
||||
if hasattr(self, 'device'):
|
||||
data = self.fronius.current_meter_data(self.device)
|
||||
else:
|
||||
data = self.fronius.current_system_meter_data()
|
||||
return data
|
22
fronius2mqtt/fronius2mqtt/mqtt.py
Normal file
22
fronius2mqtt/fronius2mqtt/mqtt.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
import logging
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
class Mqtt:
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
def connect(self):
|
||||
self.client = mqtt.Client()
|
||||
self.client.username_pw_set(self.config['user'], self.config['password'])
|
||||
self.client.connect(self.config['host'], self.config['port'])
|
||||
self.client.loop_start()
|
||||
|
||||
def disconnect(self):
|
||||
self.client.disconnect()
|
||||
|
||||
def publish(self, topic, payload):
|
||||
topic = "{}/{}".format(self.config['topic'], topic)
|
||||
logging.info("Publish %s: %s", topic, payload)
|
||||
self.client.publish(topic, payload)
|
18
fronius2mqtt/fronius2mqtt/storage.py
Normal file
18
fronius2mqtt/fronius2mqtt/storage.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
from pyfronius import fronius
|
||||
from fronius2mqtt import device
|
||||
|
||||
class Storage(device.Device):
|
||||
|
||||
def __init__(self, config):
|
||||
self.host = config['host']
|
||||
if 'device' in config:
|
||||
self.device = config['device']
|
||||
else:
|
||||
self.device = 0
|
||||
self.topic = config['topic']
|
||||
self.fronius = fronius.Fronius(self.host)
|
||||
|
||||
def update(self):
|
||||
data = self.fronius.current_storage_data(self.device)
|
||||
return data
|
17
fronius2mqtt/setup.py
Normal file
17
fronius2mqtt/setup.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup(name='fronius2mqtt',
|
||||
version='0.1',
|
||||
description='Fronius 2 MQTT bridge',
|
||||
url='https://github.com/gbeine/fronius2mqtt',
|
||||
author='Gerrit',
|
||||
author_email='mail@gerritbeine.de',
|
||||
license='MIT',
|
||||
packages=['fronius2mqtt'],
|
||||
requires=[
|
||||
'logging',
|
||||
'paho.mqtt',
|
||||
'pyfronius',
|
||||
'pyyaml',
|
||||
],
|
||||
zip_safe=False)
|
9
install
Normal file
9
install
Normal file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
python3 -m venv .
|
||||
|
||||
git clone https://github.com/gbeine/pyfronius.git
|
||||
|
||||
source bin/activate
|
||||
pip install -e pyfronius
|
||||
pip install -e fronius2mqtt
|
21
logging.conf
Normal file
21
logging.conf
Normal file
|
@ -0,0 +1,21 @@
|
|||
[loggers]
|
||||
keys=root
|
||||
|
||||
[handlers]
|
||||
keys=consoleHandler
|
||||
|
||||
[formatters]
|
||||
keys=simpleFormatter
|
||||
|
||||
[logger_root]
|
||||
level=DEBUG
|
||||
handlers=consoleHandler
|
||||
|
||||
[handler_consoleHandler]
|
||||
class=StreamHandler
|
||||
level=DEBUG
|
||||
formatter=simpleFormatter
|
||||
args=(sys.stdout,)
|
||||
|
||||
[formatter_simpleFormatter]
|
||||
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
|
Loading…
Reference in a new issue