Skip to content

Commit

Permalink
Merge pull request #3 from trizmark/add-discharge-to-grid
Browse files Browse the repository at this point in the history
Added export mode for libbi
  • Loading branch information
trizmark authored Oct 28, 2023
2 parents defb7b5 + 454d0c8 commit d3e369e
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 42 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Setup will add a cli under the name myenergicli, see below for usage

A simple cli is provided with this library.

If no username or password is supplied as input arguments and no configuration file is found you will be prompted.
If no username, password, app_email or app_password is supplied as input arguments and no configuration file is found you will be prompted.
Conifguration file will be searched for in ./.myenergi.cfg and ~/.myenergi.cfg

### Example configuration file
Expand All @@ -35,18 +35,20 @@ Conifguration file will be searched for in ./.myenergi.cfg and ~/.myenergi.cfg
[hub]
serial=12345678
password=yourpassword
app_email=myemail@email.com
app_password=yourapppassword
```

### CLI usage

```
usage: myenergi [-h] [-u USERNAME] [-p PASSWORD] [-d] [-j]
{list,overview,zappi,eddi,harvi} ...
usage: myenergi [-h] [-u USERNAME] [-p PASSWORD] [-e APP_EMAIL] [-a APP_PASSWORD] [-d] [-j]
{list,overview,zappi,eddi,harvi,libbi} ...
myenergi CLI.
positional arguments:
{list,overview,zappi,eddi,harvi}
{list,overview,zappi,eddi,harvi,libbi}
sub-command help
list list devices
overview show overview
Expand Down Expand Up @@ -150,16 +152,17 @@ Very early and basic support of Libbi.

- Reads a few values such as State of Charge, DCPV CT
- Battery in and out energy
- Gets and sets the current status
- Gets and sets the current operating mode (normal/stopped/export)
- Change priority of Libbi
- Enable/Disable charging from the grid

cli examples:
```
myenergi libbi show
myenergi libbi mode normal
myenergi libbi mode stop
myenergi libbi priority 1
myenergi libbi energy
myenergi libbi chargefromgrid disable
```


Expand Down
13 changes: 10 additions & 3 deletions pymyenergi/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,13 @@ async def main(args):
await device.set_operating_mode(args.arg[0])
print(f"Operating mode was set to {args.arg[0].capitalize()}")
elif args.action == "chargefromgrid" and args.command == LIBBI:
if len(args.arg) < 1 or args.arg[0].capitalize() not in ["True", "False"]:
sys.exit(f"A mode must be specifed, one of true or false")
if len(args.arg) < 1 or args.arg[0].capitalize() not in [
"True",
"False",
"Enable",
"Disable",
]:
sys.exit(f"A mode must be specifed, one of enable or disable")
await device.set_charge_from_grid(args.arg[0])
print(f"Charge from grid was set to {args.arg[0].capitalize()}")
elif args.action == "mingreen" and args.command == ZAPPI:
Expand Down Expand Up @@ -230,7 +235,9 @@ def cli():
LIBBI, help="use libbi --help for available commands"
)
subparser_libbi.add_argument("-s", "--serial", dest="serial", default=None)
subparser_libbi.add_argument("action", choices=["show","mode","priority","energy","chargefromgrid"])
subparser_libbi.add_argument(
"action", choices=["show", "mode", "priority", "energy", "chargefromgrid"]
)
subparser_libbi.add_argument("arg", nargs="*")

args = parser.parse_args()
Expand Down
94 changes: 61 additions & 33 deletions pymyenergi/libbi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,36 @@

_LOGGER = logging.getLogger(__name__)

MODE_NORMAL = 1
MODE_STOPPED = 0

STATES = { 0:'Off',
1:'On',
2:'Battery Full',
4:'Idle',
5:'Charging',
6:'Discharging',
7:'Duration Charging',
101:'Idle?',
102:'102',
104:'Battery Full?',
151:'FW Upgrade (ARM)',
156:'FW Upgrade (DSP)',
234:'Calibration Charge',
251:'FW Upgrade (DSP)',
252:'FW Upgrade (ARM)' }

LIBBI_MODES = ["Stopped","Normal"]
LIBBI_MODE_NAMES = ["STOP", "BALANCE"]
STATES = {
0: "Off",
1: "On",
2: "Battery Full",
4: "Idle",
5: "Charging",
6: "Discharging",
7: "Duration Charging",
8: "Duration Drain",
51: "Boosting",
53: "Boosting",
55: "Boosting",
11: "Stopped",
101: "Idle?",
102: "Full",
104: "Full",
151: "FW Upgrade (ARM)",
156: "FW Upgrade (DSP)",
234: "Calibration Charge",
251: "FW Upgrade (DSP)",
252: "FW Upgrade (ARM)",
}

LIBBI_MODES = ["Stopped", "Normal", "Export"]
LIBBI_MODE_CONFIG = {
"Stopped": {"mode_int": 0, "mode_name": "STOP"},
"Normal": {"mode_int": 1, "mode_name": "BALANCE"},
"Export": {"mode_int": 5, "mode_name": "DRAIN"},
}
"""The myenergi app defines other modes as well (capture, charge, match), but these cannot be set"""

class Libbi(BaseDevice):
"""Libbi Client for myenergi API."""
Expand All @@ -38,8 +47,13 @@ def __init__(self, connection: Connection, serialno, data={}) -> None:
super().__init__(connection, serialno, data)

async def refresh_extra(self):
chargeFromGrid = await self._connection.get("/api/AccountAccess/LibbiMode?serialNo=" + str(self.serial_number), oauth=True)
self._extra_data["charge_from_grid"] = chargeFromGrid["content"][str(self.serial_number)]
chargeFromGrid = await self._connection.get(
"/api/AccountAccess/LibbiMode?serialNo=" + str(self.serial_number),
oauth=True,
)
self._extra_data["charge_from_grid"] = chargeFromGrid["content"][
str(self.serial_number)
]

@property
def kind(self):
Expand Down Expand Up @@ -142,12 +156,12 @@ def priority(self):
@property
def battery_size(self):
"""Battery size in kwh"""
return self._data.get("mbc", 0) /1000
return self._data.get("mbc", 0) / 1000

@property
def inverter_size(self):
"""Inverter size in kwh"""
return self._data.get("mic", 0) /1000
return self._data.get("mic", 0) / 1000

@property
def grid_import(self):
Expand All @@ -173,7 +187,7 @@ def battery_discharge(self):
def generated(self):
"""Solar generation from history data"""
return self.history_data.get("generated", 0)

@property
def charge_from_grid(self):
"""Is charging from the grid enabled?"""
Expand All @@ -183,22 +197,32 @@ def charge_from_grid(self):
def prefix(self):
return "L"

def get_mode_description(self, mode: str):
"""Get the mode name as returned by myenergi API. E.g. Normal mode is BALANCE"""
for k in LIBBI_MODE_CONFIG:
if LIBBI_MODE_CONFIG[k]["mode_name"] == mode:
return k
return "???"

async def set_operating_mode(self, mode: str):
"""Stopped or normal mode"""
print("current mode", self._data["lmo"])
mode_int = LIBBI_MODES.index(mode.capitalize())
"""Set operating mode"""
print("current mode", self.get_mode_description(self._data["lmo"]))
mode_int = LIBBI_MODE_CONFIG[mode.capitalize()]["mode_int"]
await self._connection.get(
f"/cgi-libbi-mode-{self.prefix}{self._serialno}-{mode_int}"
)
self._data["lmo"] = LIBBI_MODE_NAMES[mode_int]
self._data["lmo"] = LIBBI_MODE_CONFIG[mode.capitalize()]["mode_name"]
return True

async def set_charge_from_grid(self, charge_from_grid: bool):
"""Set charge from grid"""
if charge_from_grid.capitalize() in ["Enable", "Disable"]:
charge_from_grid = (
"True" if charge_from_grid.capitalize() == "Enable" else "False"
)
await self._connection.put(
f"/api/AccountAccess/LibbiMode?chargeFromGrid={charge_from_grid}&serialNo={self._serialno}",
oauth=True
oauth=True,
)
self._extra_data["charge_from_grid"] = charge_from_grid
return True
Expand Down Expand Up @@ -229,8 +253,12 @@ def show(self, short_format=False):
ret = ret + f"Generating: {self.power_generated}W\n"
ret = ret + f"Grid: {self.power_grid}W\n"
ret = ret + f"Status : {self.status}\n"
ret = ret + f"Local Mode : {self.local_mode}\n"
ret = ret + f"Charge from Grid: {self.charge_from_grid}\n"
ret = ret + "Local Mode : " + self.get_mode_description(self.local_mode) + "\n"
ret = ret + "Charge from Grid: "
if self.charge_from_grid:
ret = ret + "Enabled\n"
else:
ret = ret + "Disabled\n"
ret = ret + f"CT 1 {self.ct1.name} {self.ct1.power}W phase {self.ct1.phase}\n"
ret = ret + f"CT 2 {self.ct2.name} {self.ct2.power}W phase {self.ct2.phase}\n"
ret = ret + f"CT 3 {self.ct3.name} {self.ct3.power}W phase {self.ct3.phase}\n"
Expand Down

0 comments on commit d3e369e

Please sign in to comment.