Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .cspell/custom-dictionary-workspace.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ coro
cprofile
creds
crosscharge
csp
customisation
Customise
cvalue
Expand Down Expand Up @@ -172,6 +173,7 @@ Ginlong
GivEnergy
givtcp
gnueabihf
greppable
gridcode
gridconsumption
gridconsumptionpower
Expand All @@ -188,6 +190,7 @@ hasattr
hass
hassapi
hassio
hazmat
heatingactive
heatingtemp
heatpump
Expand Down Expand Up @@ -326,7 +329,9 @@ perc
percnt
peterhaban
photovoltaics
pinv
pitem
pkcs1v15
pkwh
plenticore
postdata
Expand Down Expand Up @@ -359,6 +364,7 @@ pytest
pytz
randn
rarr
rawkey
reactivepower
recp
redownload
Expand Down Expand Up @@ -469,6 +475,7 @@ twinx
tzfile
tzpath
unconfigured
unfetched
unparseable
unsmoothed
unstaged
Expand Down
22 changes: 22 additions & 0 deletions apps/predbat/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from db_manager import DatabaseManager
from fox import FoxAPI
from deye import DeyeAPI
from sunsynk import SunsynkAPI
from enphase import EnphaseAPI
from kraken import KrakenAPI
from web_mcp import PredbatMCPServer
Expand Down Expand Up @@ -483,6 +484,27 @@
"phase": 1,
"can_restart": True,
},
"sunsynk": {
"class": SunsynkAPI,
"name": "Sunsynk Connect",
"event_filter": "predbat_sunsynk_",
"phase": 1,
"can_restart": True,
# key required so the component only starts for Sunsynk instances, not fleet-wide -
# Sunsynk uses a single injected-token credential (sunsynk_key), like teslemetry's
# "key", rather than deye/solis's multiple-auth-path required_or gate.
"args": {
"key": {"required": True, "config": "sunsynk_key"},
"inverter_sn": {"required": False, "config": "sunsynk_inverter_sn"},
"plant_id": {"required": False, "config": "sunsynk_plant_id"},
"automatic": {"required": False, "default": False, "config": "sunsynk_automatic"},
"automatic_ignore_pv": {"required": False, "default": False, "config": "sunsynk_automatic_ignore_pv"},
"auth_method": {"required": False, "config": "sunsynk_auth_method"},
"token_expires_at": {"required": False, "config": "sunsynk_token_expires_at"},
"token_hash": {"required": False, "config": "sunsynk_token_hash"},
"base_url": {"required": False, "default": "https://api.sunsynk.net", "config": "sunsynk_base_url"},
},
},
"load_ml": {
"class": LoadMLComponent,
"name": "ML Load Forecaster",
Expand Down
45 changes: 45 additions & 0 deletions apps/predbat/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2004,6 +2004,42 @@
"charge_discharge_with_rate": False,
"target_soc_used_for_discharge": True,
},
# Sunsynk-branded hardware is Deye hardware under the skin, and the cloud API shares the
# same 6-slot-TOU control model, "HH:MM" time format, and "%" SOC units - so this entry is
# copied verbatim from "DeyeCloud" above (only "name" differs). Sunsynk's read path (device
# discovery + telemetry publish) ships now; the control-specific fields below
# (charge_time_format, support_charge_freeze/support_discharge_freeze, has_timed_pause,
# etc.) are inherited placeholders and are inert until control lands (Task 14+) - confirm
# each one against Sunsynk's real control API before it is relied upon for writes.
"SUNSYNK": {
"name": "SUNSYNK",
"has_rest_api": False,
"has_mqtt_api": False,
"output_charge_control": "power",
"charge_control_immediate": False,
"has_charge_enable_time": True,
"has_discharge_enable_time": True,
"has_target_soc": True,
"has_reserve_soc": True,
"has_timed_pause": False,
"charge_time_format": "HH:MM",
"charge_time_entity_is_option": True,
"soc_units": "%",
"num_load_entities": 1,
"has_ge_inverter_mode": False,
"has_ge_eco_toggle": False,
"has_fox_inverter_mode": False,
"time_button_press": True,
"clock_time_format": "%Y-%m-%d %H:%M:%S",
"write_and_poll_sleep": 2,
"has_time_window": False,
"support_charge_freeze": True,
"support_discharge_freeze": True,
"has_idle_time": False,
"can_span_midnight": False,
"charge_discharge_with_rate": False,
"target_soc_used_for_discharge": True,
},
"SolaxCloud": {
"name": "SolaxCloud",
"has_rest_api": False,
Expand Down Expand Up @@ -2299,6 +2335,15 @@
"deye_inverter_sn": {"type": "string|string_list", "empty": False},
"deye_automatic": {"type": "boolean"},
"deye_automatic_ignore_pv": {"type": "boolean"},
"sunsynk_key": {"type": "string", "empty": False},
"sunsynk_inverter_sn": {"type": "string|string_list", "empty": False},
"sunsynk_plant_id": {"type": "string", "empty": False},
"sunsynk_automatic": {"type": "boolean"},
"sunsynk_automatic_ignore_pv": {"type": "boolean"},
"sunsynk_auth_method": {"type": "string", "empty": False},
"sunsynk_token_expires_at": {"type": "string", "empty": False},
"sunsynk_token_hash": {"type": "string", "empty": False},
"sunsynk_base_url": {"type": "string", "empty": False},
"teslemetry_key": {"type": "string", "empty": False},
"teslemetry_site_id": {"type": "string|string_list"},
"teslemetry_base_url": {"type": "string", "empty": False},
Expand Down
Loading
Loading