Browse Source

Merge branch 'main' into development03

pull/958/head
lumapu 2 years ago
parent
commit
ece48b3cab
  1. 13
      User_Manual.md
  2. 3
      tools/rpi/ahoy.yml.example
  3. 29
      tools/rpi/hoymiles/__init__.py
  4. 10
      tools/rpi/hoymiles/__main__.py
  5. 8
      tools/rpi/hoymiles/decoders/__init__.py

13
User_Manual.md

@ -321,6 +321,19 @@ Send Power Limit:
- A persistent limit is only needed if you want to throttle your inverter permanently or you can use it to set a start value on the battery, which is then always the switch-on limit when switching on, otherwise it would ramp up to 100% without regulation, which is continuous load is not healthy. - A persistent limit is only needed if you want to throttle your inverter permanently or you can use it to set a start value on the battery, which is then always the switch-on limit when switching on, otherwise it would ramp up to 100% without regulation, which is continuous load is not healthy.
- You can set a new limit in the turn-off state, which is then used for on (switching on again), otherwise the last limit from before the turn-off is used, but of course this only applies if DC voltage is applied the whole time. - You can set a new limit in the turn-off state, which is then used for on (switching on again), otherwise the last limit from before the turn-off is used, but of course this only applies if DC voltage is applied the whole time.
- If the DC voltage is missing for a few seconds, the microcontroller in the inverter goes off and forgets everything that was temporary/non-persistent in the RAM: YieldDay, error memory, non-persistent limit. - If the DC voltage is missing for a few seconds, the microcontroller in the inverter goes off and forgets everything that was temporary/non-persistent in the RAM: YieldDay, error memory, non-persistent limit.
### Update your AHOY-DTU Firmware
To update your AHOY-DTU, you have to download the latest firmware package.
Here are the [latest stable releases](https://github.com/lumapu/ahoy/releases/) and [latest development builds](https://nightly.link/lumapu/ahoy/workflows/compile_development/development03/ahoydtu_dev.zip) available for download.
As soon as you have downloaded the firmware package, unzip it. On the WebUI, navigate to Update and press on select firmware file.
From the unzipped files, select the right .bin file for your hardware and needs.
- If you use an ESP8266, select the file ending with esp8266.bin
- If you use an ESP8266 with prometheus, select the file ending with esp8266_prometheus.bin
- If you use an ESP32, select the file ending with esp32.bin
- If you use an ESP32 with prometheus, select the file ending with esp32_prometheus.bin
Note: if you want to use prometheus, the usage of an ESP32 is recommended, since the ESP8266 is at its performance limits and therefore can cause stability issues.
After selecting the right firmware file, press update. Your AHOY-DTU will now install the new firmware and reboot.
## Additional Notes ## Additional Notes
### MI Inverters ### MI Inverters

3
tools/rpi/ahoy.yml.example

@ -2,11 +2,14 @@
ahoy: ahoy:
interval: 5 interval: 5
transmit_retries: 5
logging: logging:
filename: 'hoymiles.log' filename: 'hoymiles.log'
# DEBUG, INFO, WARNING, ERROR, FATAL # DEBUG, INFO, WARNING, ERROR, FATAL
level: 'INFO' level: 'INFO'
max_log_filesize: 1000000
max_log_files: 1
sunset: sunset:
disabled: false disabled: false

29
tools/rpi/hoymiles/__init__.py

@ -297,8 +297,8 @@ class InverterPacketFragment:
class HoymilesNRF: class HoymilesNRF:
"""Hoymiles NRF24 Interface""" """Hoymiles NRF24 Interface"""
tx_channel_id = 0 tx_channel_id = 2
tx_channel_list = [40] tx_channel_list = [3,23,40,61,75]
rx_channel_id = 0 rx_channel_id = 0
rx_channel_list = [3,23,40,61,75] rx_channel_list = [3,23,40,61,75]
rx_channel_ack = False rx_channel_ack = False
@ -332,6 +332,12 @@ class HoymilesNRF:
:rtype: bool :rtype: bool
""" """
self.next_tx_channel()
if HOYMILES_TRANSACTION_LOGGING:
c_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
logging.debug(f'{c_datetime} Transmit {len(packet)} bytes channel {self.tx_channel}: {hexify_payload(packet)}')
if not txpower: if not txpower:
txpower = self.txpower txpower = self.txpower
@ -363,13 +369,13 @@ class HoymilesNRF:
""" """
Receive Packets Receive Packets
:param timeout: receive timeout in nanoseconds (default: 12e8) :param timeout: receive timeout in nanoseconds (default: 5e8)
:type timeout: int :type timeout: int
:yields: fragment :yields: fragment
""" """
if not timeout: if not timeout:
timeout=12e8 timeout=5e8
self.radio.setChannel(self.rx_channel) self.radio.setChannel(self.rx_channel)
self.radio.setAutoAck(False) self.radio.setAutoAck(False)
@ -415,7 +421,7 @@ class HoymilesNRF:
self.radio.setChannel(self.rx_channel) self.radio.setChannel(self.rx_channel)
self.radio.startListening() self.radio.startListening()
time.sleep(0.005) time.sleep(0.004)
def next_rx_channel(self): def next_rx_channel(self):
""" """
@ -433,6 +439,15 @@ class HoymilesNRF:
return True return True
return False return False
def next_tx_channel(self):
"""
Select next channel from hop list
"""
self.tx_channel_id = self.tx_channel_id + 1
if self.tx_channel_id >= len(self.tx_channel_list):
self.tx_channel_id = 0
@property @property
def tx_channel(self): def tx_channel(self):
""" """
@ -612,10 +627,6 @@ class InverterTransaction:
packet = self.tx_queue.pop(0) packet = self.tx_queue.pop(0)
if HOYMILES_TRANSACTION_LOGGING:
c_datetime = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
logging.debug(f'{c_datetime} Transmit {len(packet)} | {hexify_payload(packet)}')
self.radio.transmit(packet, txpower=self.txpower) self.radio.transmit(packet, txpower=self.txpower)
wait = False wait = False

10
tools/rpi/hoymiles/__main__.py

@ -19,6 +19,7 @@ import yaml
from yaml.loader import SafeLoader from yaml.loader import SafeLoader
import hoymiles import hoymiles
import logging import logging
from logging.handlers import RotatingFileHandler
################################################################################ ################################################################################
""" Signal Handler """ """ Signal Handler """
@ -127,6 +128,7 @@ def main_loop(ahoy_config):
dtu_name = ahoy_config.get('dtu', {}).get('name', 'hoymiles-dtu') dtu_name = ahoy_config.get('dtu', {}).get('name', 'hoymiles-dtu')
sunset.sun_status2mqtt(dtu_ser, dtu_name) sunset.sun_status2mqtt(dtu_ser, dtu_name)
loop_interval = ahoy_config.get('interval', 1) loop_interval = ahoy_config.get('interval', 1)
transmit_retries = ahoy_config.get('transmit_retries', 5)
try: try:
do_init = True do_init = True
@ -143,7 +145,7 @@ def main_loop(ahoy_config):
sys.exit(999) sys.exit(999)
if hoymiles.HOYMILES_DEBUG_LOGGING: if hoymiles.HOYMILES_DEBUG_LOGGING:
logging.info(f'Poll inverter name={inverter["name"]} ser={inverter["serial"]}') logging.info(f'Poll inverter name={inverter["name"]} ser={inverter["serial"]}')
poll_inverter(inverter, dtu_ser, do_init, 3) poll_inverter(inverter, dtu_ser, do_init, transmit_retries)
do_init = False do_init = False
if loop_interval > 0: if loop_interval > 0:
@ -298,6 +300,8 @@ def init_logging(ahoy_config):
log_config = ahoy_config.get('logging') log_config = ahoy_config.get('logging')
fn = 'hoymiles.log' fn = 'hoymiles.log'
lvl = logging.ERROR lvl = logging.ERROR
max_log_filesize = 1000000
max_log_files = 1
if log_config: if log_config:
fn = log_config.get('filename', fn) fn = log_config.get('filename', fn)
level = log_config.get('level', 'ERROR') level = log_config.get('level', 'ERROR')
@ -311,9 +315,11 @@ def init_logging(ahoy_config):
lvl = logging.ERROR lvl = logging.ERROR
elif level == 'FATAL': elif level == 'FATAL':
lvl = logging.FATAL lvl = logging.FATAL
max_log_filesize = log_config.get('max_log_filesize', max_log_filesize)
max_log_files = log_config.get('max_log_files', max_log_files)
if hoymiles.HOYMILES_TRANSACTION_LOGGING: if hoymiles.HOYMILES_TRANSACTION_LOGGING:
lvl = logging.DEBUG lvl = logging.DEBUG
logging.basicConfig(filename=fn, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=lvl) logging.basicConfig(handlers=[RotatingFileHandler(fn, maxBytes=max_log_filesize, backupCount=max_log_files)], format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=lvl)
dtu_name = ahoy_config.get('dtu',{}).get('name','hoymiles-dtu') dtu_name = ahoy_config.get('dtu',{}).get('name','hoymiles-dtu')
logging.info(f'start logging for {dtu_name} with level: {logging.root.level}') logging.info(f'start logging for {dtu_name} with level: {logging.root.level}')

8
tools/rpi/hoymiles/decoders/__init__.py

@ -515,9 +515,17 @@ class Hm300Decode0B(StatusResponse):
""" reactive power """ """ reactive power """
return self.unpack('>H', 20)[0]/10 return self.unpack('>H', 20)[0]/10
@property @property
def powerfactor(self):
""" Powerfactor """
return self.unpack('>H', 24)[0]/1000
@property
def temperature(self): def temperature(self):
""" Inverter temperature in °C """ """ Inverter temperature in °C """
return self.unpack('>h', 26)[0]/10 return self.unpack('>h', 26)[0]/10
@property
def event_count(self):
""" Event counter """
return self.unpack('>H', 28)[0]
class Hm300Decode0C(Hm300Decode0B): class Hm300Decode0C(Hm300Decode0B):
""" 1121-series mirco-inverters status data """ """ 1121-series mirco-inverters status data """

Loading…
Cancel
Save