Skip to content

Commit

Permalink
Inverter support (#54)
Browse files Browse the repository at this point in the history
* inverter client

* scale fixes

* Update README.md
  • Loading branch information
cyrils authored Jan 1, 2024
1 parent b78db25 commit 8f9f29b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 2 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ DEBUG:root:BT-TH-30A3XXXX => {'function': 'READ', 'daily_power_generation': [175
# Battery output
DEBUG:root:BT-TH-161EXXXX => {'function': 'READ', 'model': 'RBT100LFP12S-G', 'cell_count': 4, 'cell_voltage_0': 3.6, 'cell_voltage_1': 3.6, 'cell_voltage_2': 3.6, 'cell_voltage_3': 3.6, 'sensor_count': 4, 'temperature_0': 21.0, 'temperature_1': 21.0, 'temperature_2': 21.0, 'temperature_3': 21.0, 'current': 1.4, 'voltage': 14.5, 'remaining_charge': 99.941, 'capacity': 100.0, 'device_id': 48}
```
```
# Inverter output (Experimental)
DEBUG:root:BT-TH-F26EXXXX => {'function': 'READ', 'uei_voltage': 123.9, 'uei_current': 0, 'voltage': 120.0, 'load_current': 2, 'frequency': 60.01, 'temperature': 54.0, 'model': 'RIV4835CSH1S', 'solar_voltage': 93.9, 'solar_current': 0.3, 'solar_power': 32, 'solar_charging_state': 'mppt', 'solar_charging_power': 32, 'load_power': 23, 'charging_current': 0, 'battery_type': 'lithium', '__device': 'BT-TH-F26EXXXX', '__client': 'InverterClient'}
```

**Have multiple devices in Hub mode?**

Expand Down Expand Up @@ -119,6 +123,7 @@ If you want to monitor real-time data, turn on polling in `config.ini` for conti
| Renogy Battery RBT100LFP12S | BT-2 ||
| Renogy Battery RBT100LFP12-BT / RBT200LFP12-BT (Built-in BLE)| - ||
| Renogy Battery RBT50LFP48S | BT-2 ||
| Renogy Inverter RIV4835CSH1S| BT-2 ||
| RICH SOLAR 20/40/60 | BT-1 ||
| SRNE ML24/ML48 Series | BT-1 ||

Expand Down
1 change: 1 addition & 0 deletions config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type = RNG_CTRL
# RNG_CTRL => Charge Controller (Rover/Wanderer/Adventurer)
# RNG_CTRL_HIST => Charge Controller historical data
# RNG_BATT => Smart Battery
# RNG_INVT => Inverter
device_id = 255 # modify if hub mode or daisy chain (see readme)

[data]
Expand Down
4 changes: 3 additions & 1 deletion example.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import configparser
import os
import sys
from renogybt import RoverClient, RoverHistoryClient, BatteryClient, DataLogger, Utils
from renogybt import InverterClient, RoverClient, RoverHistoryClient, BatteryClient, DataLogger, Utils

logging.basicConfig(level=logging.DEBUG)

Expand Down Expand Up @@ -32,5 +32,7 @@ def on_data_received(client, data):
RoverHistoryClient(config, on_data_received).connect()
elif config['device']['type'] == 'RNG_BATT':
BatteryClient(config, on_data_received).connect()
elif config['device']['type'] == 'RNG_INVT':
InverterClient(config, on_data_received).connect()
else:
logging.error("unknown device type")
1 change: 0 additions & 1 deletion renogybt/BatteryClient.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import logging
from .BaseClient import BaseClient
from .Utils import bytes_to_int, format_temperature

Expand Down
80 changes: 80 additions & 0 deletions renogybt/InverterClient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import logging
from .BaseClient import BaseClient
from .Utils import bytes_to_int

FUNCTION = {
3: "READ",
6: "WRITE"
}

CHARGING_STATE = {
0: 'deactivated',
1: 'activated',
2: 'mppt',
3: 'equalizing',
4: 'boost',
5: 'floating',
6: 'current limiting'
}

BATTERY_TYPE = {
1: 'open',
2: 'sealed',
3: 'gel',
4: 'lithium',
5: 'custom'
}

class InverterClient(BaseClient):
def __init__(self, config, on_data_callback=None):
super().__init__(config)
self.on_data_callback = on_data_callback
self.data = { 'function': 'READ' }
self.sections = [
{'register': 4000, 'words': 8, 'parser': self.parse_inverter_stats},
{'register': 4311, 'words': 8, 'parser': self.parse_inverter_model},
{'register': 4329, 'words': 5, 'parser': self.parse_solar_charging},
{'register': 4410, 'words': 2, 'parser': self.parse_inverter_load},
{'register': 57348, 'words': 1, 'parser': self.parse_battery_type}
]

def parse_inverter_stats(self, bs):
logging.info(f"parse_inverter_stats {bs.hex()}")
data = {}
data['function'] = FUNCTION.get(bytes_to_int(bs, 1, 1))
data['uei_voltage'] = bytes_to_int(bs, 3, 2, scale=0.1)
data['uei_current'] = bytes_to_int(bs, 5, 2, scale=0.1)
data['voltage'] = bytes_to_int(bs, 7, 2, scale=0.1)
data['load_current'] = bytes_to_int(bs, 9, 2)
data['frequency'] = bytes_to_int(bs, 11, 2, scale=0.01)
data['temperature'] = bytes_to_int(bs, 13, 2, scale=0.1)
self.data.update(data)

def parse_inverter_model(self, bs):
logging.info(f"parse_inverter_model {bs.hex()}")
data = {}
data['model'] = (bs[3:15]).decode('utf-8')
self.data.update(data)

def parse_solar_charging(self, bs):
logging.info(f"parse_solar_charging {bs.hex()}")
data = {}
data['solar_voltage'] = bytes_to_int(bs, 3, 2, scale=0.1)
data['solar_current'] = bytes_to_int(bs, 5, 2, scale=0.1)
data['solar_power'] = bytes_to_int(bs, 7, 2)
data['solar_charging_state'] = CHARGING_STATE.get(bytes_to_int(bs, 9, 2))
data['solar_charging_power'] = bytes_to_int(bs, 11, 2)
self.data.update(data)

def parse_inverter_load(self, bs):
logging.info(f"parse_inverter_load {bs.hex()}")
data = {}
data['load_power'] = bytes_to_int(bs, 3, 2)
data['charging_current'] = bytes_to_int(bs, 5, 2, scale=0.1)
self.data.update(data)

def parse_battery_type(self, bs):
data = {}
data['function'] = FUNCTION.get(bytes_to_int(bs, 1, 1))
data['battery_type'] = BATTERY_TYPE.get(bytes_to_int(bs, 3, 2))
self.data.update(data)

0 comments on commit 8f9f29b

Please sign in to comment.