mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-03 04:05:55 +02:00
Merge branch 'Argafal-hms' into hms
This commit is contained in:
commit
363d26b5b2
11 changed files with 89 additions and 17 deletions
|
@ -217,6 +217,14 @@ Once your Ahoy DTU is running, you can use the Over The Air (OTA) capabilities t
|
||||||
|
|
||||||
! ATTENTION: If you update from a very low version to the newest, please make sure to wipe all flash data!
|
! ATTENTION: If you update from a very low version to the newest, please make sure to wipe all flash data!
|
||||||
|
|
||||||
|
#### Flashing on Linux with `esptool.py` (ESP32)
|
||||||
|
1. install [esptool.py](https://docs.espressif.com/projects/esptool/en/latest/esp32/) if you haven't already.
|
||||||
|
2. download and extract the latest release bin-file from [ahoy_](https://github.com/grindylow/ahoy/releases)
|
||||||
|
3. `cd ahoy_v<XXX> && cp *esp32.bin esp32.bin`
|
||||||
|
4. Perhaps you need to replace `/dev/ttyUSB0` to match your acual device in the following command. Execute it afterwards: `esptool.py --port /dev/ttyUSB0 --chip esp32 --before default_reset --after hard_reset write_flash --flash_mode dout --flash_freq 40m --flash_size detect 0x1000 bootloader.bin 0x8000 partitions.bin 0x10000 esp32.bin`
|
||||||
|
5. Unplug and replug your device.
|
||||||
|
6. Open a serial monitor (e.g. Putty) @ 115200 Baud. You should see some messages regarding wifi.
|
||||||
|
|
||||||
## Connect to your Ahoy DTU
|
## Connect to your Ahoy DTU
|
||||||
|
|
||||||
When everything is wired up and the firmware is flashed, it is time to connect to your Ahoy DTU.
|
When everything is wired up and the firmware is flashed, it is time to connect to your Ahoy DTU.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
# Development Changes
|
# Development Changes
|
||||||
|
|
||||||
|
## 0.6.13 - 2023-05-16
|
||||||
|
* merge PR #934 (fix JSON API) and #944 (update manual)
|
||||||
|
|
||||||
## 0.6.12 - 2023-04-28
|
## 0.6.12 - 2023-04-28
|
||||||
* improved MqTT
|
* improved MqTT
|
||||||
* fix menu active item
|
* fix menu active item
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 6
|
#define VERSION_MINOR 6
|
||||||
#define VERSION_PATCH 12
|
#define VERSION_PATCH 13
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -84,8 +84,8 @@ class HmRadio {
|
||||||
DTU_RADIO_ID = ((uint64_t)(((dtuSn >> 24) & 0xFF) | ((dtuSn >> 8) & 0xFF00) | ((dtuSn << 8) & 0xFF0000) | ((dtuSn << 24) & 0xFF000000)) << 8) | 0x01;
|
DTU_RADIO_ID = ((uint64_t)(((dtuSn >> 24) & 0xFF) | ((dtuSn >> 8) & 0xFF00) | ((dtuSn << 8) & 0xFF0000) | ((dtuSn << 24) & 0xFF000000)) << 8) | 0x01;
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
|
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||||
mSpi = new SPIClass(FSPI);
|
mSpi = new SPIClass(HSPI);
|
||||||
#else
|
#else
|
||||||
mSpi = new SPIClass(VSPI);
|
mSpi = new SPIClass(VSPI);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,12 +11,21 @@
|
||||||
#include "driver/spi_master.h"
|
#include "driver/spi_master.h"
|
||||||
#include "esp_rom_gpio.h" // for esp_rom_gpio_connect_out_signal
|
#include "esp_rom_gpio.h" // for esp_rom_gpio_connect_out_signal
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
#define CLK_PIN 6
|
||||||
|
#define MOSI_PIN 5
|
||||||
|
#else
|
||||||
#define CLK_PIN 18
|
#define CLK_PIN 18
|
||||||
#define MOSI_PIN 23
|
#define MOSI_PIN 23
|
||||||
#define MISO_PIN -1
|
#endif
|
||||||
|
|
||||||
#define SPI_CLK 1 * 1000 * 1000 // 1MHz
|
#define SPI_CLK 1 * 1000 * 1000 // 1MHz
|
||||||
|
|
||||||
|
#define SPI_PARAM_LOCK() \
|
||||||
|
do { \
|
||||||
|
} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS)
|
||||||
|
#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock)
|
||||||
|
|
||||||
// for ESP32 this is the so-called HSPI
|
// for ESP32 this is the so-called HSPI
|
||||||
// for ESP32-S2/S3/C3 this nomenclature does not really exist anymore,
|
// for ESP32-S2/S3/C3 this nomenclature does not really exist anymore,
|
||||||
// it is simply the first externally usable hardware SPI master controller
|
// it is simply the first externally usable hardware SPI master controller
|
||||||
|
@ -30,9 +39,10 @@ class esp32_3wSpi {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup(uint8_t pinCsb = CSB_PIN, uint8_t pinFcsb = FCSB_PIN) { //, uint8_t pinGpio3 = GPIO3_PIN) {
|
void setup(uint8_t pinCsb = CSB_PIN, uint8_t pinFcsb = FCSB_PIN) { //, uint8_t pinGpio3 = GPIO3_PIN) {
|
||||||
|
paramLock = xSemaphoreCreateMutex();
|
||||||
spi_bus_config_t buscfg = {
|
spi_bus_config_t buscfg = {
|
||||||
.mosi_io_num = MOSI_PIN,
|
.mosi_io_num = MOSI_PIN,
|
||||||
.miso_io_num = MISO_PIN,
|
.miso_io_num = -1, // single wire MOSI/MISO
|
||||||
.sclk_io_num = CLK_PIN,
|
.sclk_io_num = CLK_PIN,
|
||||||
.quadwp_io_num = -1,
|
.quadwp_io_num = -1,
|
||||||
.quadhd_io_num = -1,
|
.quadhd_io_num = -1,
|
||||||
|
@ -93,7 +103,9 @@ class esp32_3wSpi {
|
||||||
.tx_buffer = &tx_data,
|
.tx_buffer = &tx_data,
|
||||||
.rx_buffer = NULL
|
.rx_buffer = NULL
|
||||||
};
|
};
|
||||||
|
SPI_PARAM_LOCK();
|
||||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
||||||
|
SPI_PARAM_UNLOCK();
|
||||||
delayMicroseconds(100);
|
delayMicroseconds(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +122,10 @@ class esp32_3wSpi {
|
||||||
.tx_buffer = NULL,
|
.tx_buffer = NULL,
|
||||||
.rx_buffer = &rx_data
|
.rx_buffer = &rx_data
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SPI_PARAM_LOCK();
|
||||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t));
|
||||||
|
SPI_PARAM_UNLOCK();
|
||||||
delayMicroseconds(100);
|
delayMicroseconds(100);
|
||||||
return rx_data;
|
return rx_data;
|
||||||
}
|
}
|
||||||
|
@ -126,11 +141,13 @@ class esp32_3wSpi {
|
||||||
.rx_buffer = NULL
|
.rx_buffer = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SPI_PARAM_LOCK();
|
||||||
for(uint8_t i = 0; i < len; i++) {
|
for(uint8_t i = 0; i < len; i++) {
|
||||||
tx_data = ~buf[i]; // negate buffer contents
|
tx_data = ~buf[i]; // negate buffer contents
|
||||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
||||||
delayMicroseconds(4); // > 4 us
|
delayMicroseconds(4); // > 4 us
|
||||||
}
|
}
|
||||||
|
SPI_PARAM_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void readFifo(uint8_t buf[], uint8_t len) {
|
void readFifo(uint8_t buf[], uint8_t len) {
|
||||||
|
@ -145,16 +162,19 @@ class esp32_3wSpi {
|
||||||
.rx_buffer = &rx_data
|
.rx_buffer = &rx_data
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SPI_PARAM_LOCK();
|
||||||
for(uint8_t i = 0; i < len; i++) {
|
for(uint8_t i = 0; i < len; i++) {
|
||||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t));
|
||||||
delayMicroseconds(4); // > 4 us
|
delayMicroseconds(4); // > 4 us
|
||||||
buf[i] = rx_data;
|
buf[i] = rx_data;
|
||||||
}
|
}
|
||||||
|
SPI_PARAM_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
spi_device_handle_t spi_reg, spi_fifo;
|
spi_device_handle_t spi_reg, spi_fifo;
|
||||||
bool mInitialized;
|
bool mInitialized;
|
||||||
|
SemaphoreHandle_t paramLock = NULL;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
template<uint8_t CSB_PIN=5, uint8_t FCSB_PIN=4>
|
template<uint8_t CSB_PIN=5, uint8_t FCSB_PIN=4>
|
||||||
|
|
|
@ -563,7 +563,7 @@ class RestApi {
|
||||||
|
|
||||||
if(F("power") == jsonIn[F("cmd")])
|
if(F("power") == jsonIn[F("cmd")])
|
||||||
accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff);
|
accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff);
|
||||||
else if(F("restart") == jsonIn[F("restart")])
|
else if(F("restart") == jsonIn[F("cmd")])
|
||||||
accepted = iv->setDevControlRequest(Restart);
|
accepted = iv->setDevControlRequest(Restart);
|
||||||
else if(0 == strncmp("limit_", jsonIn[F("cmd")].as<const char*>(), 6)) {
|
else if(0 == strncmp("limit_", jsonIn[F("cmd")].as<const char*>(), 6)) {
|
||||||
iv->powerLimit[0] = jsonIn["val"];
|
iv->powerLimit[0] = jsonIn["val"];
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}')
|
||||||
|
|
||||||
|
|
|
@ -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…
Add table
Reference in a new issue