Browse Source

Merge branch 'development03' into asyncWeb03

pull/283/head
lumapu 2 years ago
parent
commit
bd93622d8f
  1. 39
      README.md
  2. BIN
      doc/Wiring_ESP32_Schematic.png
  3. BIN
      doc/Wiring_ESP32_Symbol.png
  4. 22
      tools/esp8266/README.md
  5. 50
      tools/rpi/ahoy.yml.example
  6. 2
      tools/rpi/hoymiles/__init__.py
  7. 54
      tools/rpi/hoymiles/outputs.py

39
README.md

@ -1,28 +1,35 @@
![actions/workflows/compile_esp8266.yml](../../actions/workflows/compile_esp8266.yml/badge.svg) ![actions/workflows/compile_development.yml](../../actions/workflows/compile_development.yml/badge.svg) ![actions/workflows/compile_esp8266.yml](../../actions/workflows/compile_esp8266.yml/badge.svg) ![actions/workflows/compile_development.yml](../../actions/workflows/compile_development.yml/badge.svg)
# 🖐 Ahoy!
![Logo](https://github.com/grindylow/ahoy/blob/main/doc/logo1_small.png?raw=true) ![Logo](https://github.com/grindylow/ahoy/blob/main/doc/logo1_small.png?raw=true)
# ahoy **Communicate with Hoymiles inverters via radio**. Get actual values like power, current, daily energy and set parameters like the power limit via web interface or MQTT. In this repository you will find different approaches means Hardware / Software to realize the described functionalities.
Ahoy is a project to bypass the original Hoymiles cloud solution.
In order to use this project, it is important what the area of ​​​​application looks like.
With each version it is necessary to have an NRF24L01+.
Click on the link below you are interested in. List of approaches
There you will find further explanations on how to proceed. (*Note: It is still under construction!*)
##### Most updated section - [ESP8266/ESP32, C++](tools/esp8266/) 👈 the most effort is spent here
- [ESP8266](tools/esp8266/) that includes an web interface - [Arduino Nano, C++](tools/nano/NRF24_SendRcv/)
- [Raspberry Pi, Python](tools/rpi/)
- [Others, C/C++](tools/nano/NRF24_SendRcv/)
##### will be updated as needed ## Quick Start with ESP8266
- [Arduino Nano](tools/nano/NRF24_SendRcv/) - [Go here ✨](https://github.com/grindylow/ahoy/blob/ahoy_v0.5.16/tools/esp8266/README.md#things-needed)
- [Raspberry Pi](tools/rpi/)
- [others](tools/nano/NRF24_SendRcv/)
If errors occur or you have suggestions for ideas, please feel free to contact us [here](https://github.com/grindylow/ahoy/issues).
## Contact ## Success Stories
We run a Discord Server that can be used to get in touch with the Developers and Users. - [Getting the data into influxDB and visualize them in a Grafana Dashboard](https://grafana.com/grafana/dashboards/16850-pv-power-ahoy/) (thx @Carl)
https://discord.gg/WzhxEY62mB ## Support, Feedback, Information and Discussion
- [Discord Server (~ 300 Users)](https://discord.gg/WzhxEY62mB)
- [The root of development](https://www.mikrocontroller.net/topic/525778)
### Development
If you encounter issues use the issues here on github.
Please try to describe your issues as precise as possible and think about if this is a issue with the software here in the repository or other software components.
**Contributors are always welcome!** **Contributors are always welcome!**
### Related Projects
- [OpenDTU](https://github.com/tbnobody/OpenDTU)
- [DTU Simulator](https://github.com/Ziyatoe/DTUsimMI1x00-Hoymiles)

BIN
doc/Wiring_ESP32_Schematic.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
doc/Wiring_ESP32_Symbol.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

22
tools/esp8266/README.md

@ -76,11 +76,29 @@ Additional, there are 3 pins, which can be set individual:
#### ESP8266 wiring example #### ESP8266 wiring example
This is an example wiring using a Wemos D1 mini.<br> This is an example wiring using a Wemos D1 mini.<br>
<img src="https://github.com/grindylow/ahoy/blob/main/doc/AhoyWemos_Steckplatine.jpg" width="300"> ##### Schematic
<img src="https://github.com/grindylow/ahoy/blob/main/doc/AhoyWemos_Schaltplan.jpg" width="300"> ![Schematic](../../doc/AhoyWemos_Schaltplan.jpg)
##### Symbolic view
![Symbolic](../../doc/AhoyWemos_Steckplatine.jpg)
#### ESP32 wiring example
Example wiring for a 38pin ESP32 module
##### Schematic
![Schematic](../../doc/Wiring_ESP32_Schematic.png)
##### Symbolic view
![Symbolic](../../doc/Wiring_ESP32_Symbol.png)
##### ESP32 GPIO settings
For this wiring, set the 3 individual GPIOs under the /setup URL:
```
CS D1 (GPIO5)
CE D2 (GPIO4)
IRQ D0 (GPIO16 - no IRQ!)
```
## Flash the Firmware on your Ahoy DTU Hardware ## Flash the Firmware on your Ahoy DTU Hardware
Once your Hardware is ready to run, you need to flash the Ahoy DTU Firmware to your Board. Once your Hardware is ready to run, you need to flash the Ahoy DTU Firmware to your Board.

50
tools/rpi/ahoy.yml.example

@ -30,30 +30,32 @@ ahoy:
volkszaehler: volkszaehler:
disabled: true disabled: true
url: 'http://localhost/middleware/' inverters:
channels: - serial: 114172220003
- type: 'temperature' url: 'http://localhost/middleware/'
uid: 'ad578a40-1d97-11ed-8e8b-fda01a416575' channels:
- type: 'frequency' - type: 'temperature'
uid: '' uid: 'ad578a40-1d97-11ed-8e8b-fda01a416575'
- type: 'ac_power0' - type: 'frequency'
uid: '7ca5ac50-1e41-11ed-927f-610c4cb2c69e' uid: ''
- type: 'ac_voltage0' - type: 'ac_power0'
uid: '9a38e2e0-1d94-11ed-b539-25f8607ac030' uid: '7ca5ac50-1e41-11ed-927f-610c4cb2c69e'
- type: 'ac_current0' - type: 'ac_voltage0'
uid: 'a9a4daf0-1e41-11ed-b68c-eb73eef3d21d' uid: '9a38e2e0-1d94-11ed-b539-25f8607ac030'
- type: 'dc_power0' - type: 'ac_current0'
uid: '38eb3ca0-1e53-11ed-b830-792e70a592fa' uid: 'a9a4daf0-1e41-11ed-b68c-eb73eef3d21d'
- type: 'dc_voltage0' - type: 'dc_power0'
uid: '' uid: '38eb3ca0-1e53-11ed-b830-792e70a592fa'
- type: 'dc_current0' - type: 'dc_voltage0'
uid: '' uid: ''
- type: 'dc_power1' - type: 'dc_current0'
uid: '51c0e9d0-1e53-11ed-b574-8bc81547eb8f' uid: ''
- type: 'dc_voltage1' - type: 'dc_power1'
uid: '' uid: '51c0e9d0-1e53-11ed-b574-8bc81547eb8f'
- type: 'dc_current1' - type: 'dc_voltage1'
uid: '' uid: ''
- type: 'dc_current1'
uid: ''
dtu: dtu:
serial: 99978563001 serial: 99978563001

2
tools/rpi/hoymiles/__init__.py

@ -647,7 +647,7 @@ class InverterTransaction:
self.time_rx = end_frame.time_rx self.time_rx = end_frame.time_rx
tr_len = end_frame.seq - 0x80 tr_len = end_frame.seq - 0x80
except StopIteration: except StopIteration:
seq_last = max(frames, key=lambda frame:frame.seq).seq seq_last = max(frames, key=lambda frame:frame.seq).seq if len(frames) else 0
self.__retransmit_frame(seq_last + 1) self.__retransmit_frame(seq_last + 1)
raise BufferError(f'Missing packet: Last packet {len(self.scratch)}') raise BufferError(f'Missing packet: Last packet {len(self.scratch)}')

54
tools/rpi/hoymiles/outputs.py

@ -208,14 +208,10 @@ try:
except ModuleNotFoundError: except ModuleNotFoundError:
pass pass
class VolkszaehlerOutputPlugin(OutputPluginFactory): class VzInverterOutput:
def __init__(self, config, **params): def __init__(self, config, session):
""" self.session = session
Initialize VolkszaehlerOutputPlugin self.serial = config.get('serial')
"""
super().__init__(**params)
self.session = requests.Session()
self.baseurl = config.get('url', 'http://localhost/middleware/') self.baseurl = config.get('url', 'http://localhost/middleware/')
self.channels = dict() self.channels = dict()
for channel in config.get('channels', []): for channel in config.get('channels', []):
@ -224,7 +220,7 @@ class VolkszaehlerOutputPlugin(OutputPluginFactory):
if uid and ctype: if uid and ctype:
self.channels[ctype] = uid self.channels[ctype] = uid
def store_status(self, response, **params): def store_status(self, data, session):
""" """
Publish StatusResponse object Publish StatusResponse object
@ -232,15 +228,9 @@ class VolkszaehlerOutputPlugin(OutputPluginFactory):
:raises ValueError: when response is not instance of StatusResponse :raises ValueError: when response is not instance of StatusResponse
""" """
if not isinstance(response, StatusResponse):
raise ValueError('Data needs to be instance of StatusResponse')
if len(self.channels) == 0: if len(self.channels) == 0:
return return
data = response.__dict__()
ts = int(round(data['time'].timestamp() * 1000)) ts = int(round(data['time'].timestamp() * 1000))
# AC Data # AC Data
@ -277,3 +267,37 @@ class VolkszaehlerOutputPlugin(OutputPluginFactory):
raise ValueError('Could not send request (%s)' % url) raise ValueError('Could not send request (%s)' % url)
except ConnectionError as e: except ConnectionError as e:
raise ValueError('Could not send request (%s)' % e) raise ValueError('Could not send request (%s)' % e)
class VolkszaehlerOutputPlugin(OutputPluginFactory):
def __init__(self, config, **params):
"""
Initialize VolkszaehlerOutputPlugin
"""
super().__init__(**params)
self.session = requests.Session()
self.inverters = dict()
for inverterconfig in config.get('inverters', []):
serial = inverterconfig.get('serial')
output = VzInverterOutput(inverterconfig, self.session)
self.inverters[serial] = output
def store_status(self, response, **params):
"""
Publish StatusResponse object
:param hoymiles.decoders.StatusResponse response: StatusResponse object
:raises ValueError: when response is not instance of StatusResponse
"""
if not isinstance(response, StatusResponse):
raise ValueError('Data needs to be instance of StatusResponse')
if len(self.inverters) == 0:
return
data = response.__dict__()
serial = data["inverter_ser"]
if serial in self.inverters:
output = self.inverters[serial]
output.store_status(data, self.session)

Loading…
Cancel
Save