Skip to content

Feature request: native local Deye/Solarman support and safe migration from SK #5501

Open

Description

@arturonaredo

Is your feature request related to a problem? Please describe.

Please consider explicit native support for local Deye inverters exposed through
Home Assistant's Solarman integration
, with a documented path from existing
inverter_type: SK configurations.

The local-control problem is already reported in #3895: Predbat can calculate a
plan while the Deye six-row Time of Use (ToU) table does not reliably express it,
leading users to add another HA automation as a translator. This issue tracks
the broader adoption, compatibility and commissioning requirements, not a
duplicate report of that specific failure.

Draft implementation: #5497. A dedicated adoption issue was missing when that
PR was opened; this issue supplies the tracking and maintainer-design discussion.
The proposed local DEYE profile is distinct from DeyeCloud and must not change
existing SK behaviour or imply that every Deye model/firmware is supported.

Describe the solution you'd like

A native, opt-in local adapter owned by Predbat's existing inverter executor,
without another planner, competing HA control automation, cloud dependency or
additional hardware polling loop.

The current proposal in #5497 provides:

  • Explicit mappings for all six ToU rows: SOC, discharge-power ceiling and
    charging source. Native windows are virtual; all rows express the current
    control intent while their physical boundaries remain unchanged.
  • Validation of distinct, ordered boundaries and supported operating settings;
    reject inconsistent configurations rather than silently rewrite them.
  • Demand, full-rate grid charge and an explicitly commissioned hold contract,
    plus bounded per-period discharge power and existing manual SOC floors.
  • Disabled-by-default control, read-only guards, source-disable interlocks,
    bounded retries and visible failures.
  • An isolated shadow path that exercises the actual translator without calling
    physical services. Timetable repair or hold commissioning in a simulation is
    labelled as a hypothesis, not a completed physical operation.
  • Honest acknowledgement semantics: an HA state match is observed, not proof
    that the physical inverter applied the setting. Solarman can expose optimistic
    post-write states. Control entities echo Predbat's own writes on Deye/Fox/Enphase, so write read-back can't detect external changes #4636 describes a related distinction for cloud components;
    it is context, not evidence of an identical implementation in local Solarman.

Adoption and promotion gates

These are proposed requirements for maintainer discussion, not a claim of approval:

  • Agree the local adapter/profile boundary and naming relative to SK and
    DeyeCloud, including a clear supported and unsupported feature list.
  • Review the native control mapping and disabled-path compatibility tests;
    no new global capability override or regression for existing inverter profiles.
  • Publish a tested model/firmware/Solarman compatibility matrix and entity
    requirements, including numeric step sizes and timestamp limitations.
  • Physically validate charge, demand, hold/PV behaviour, limited discharge,
    all six rows, target changes and midnight transitions on supported equipment.
  • Document safe migration from SK: entity mapping, coherent table
    boundaries, existing current/SOC/export limits, sole controller and rollback.
    Do not blindly reuse a grid-charge-start entity as a discharge reserve.
  • Document behaviour when Predbat/HA stops, telemetry is unavailable or a
    write is rejected. The present immediate-control proposal can leave the last
    physical table in place; shadow tests do not establish an independent watchdog.
  • Complete upstream CI/review and commissioning evidence before describing
    this experimental adapter as generally adopted support.

Global current limits, BMS/shutdown protections, export policy, operating modes
and EV relays must not be silently rewritten as part of local-adapter adoption.
Electrical topology and capacity remain installation-specific commissioning
questions, not conclusions derived from nominal ratings or simulation.

Describe alternatives you've considered

  • Keep using SK with custom service templates: preserves existing setups but
    does not provide a dedicated six-row contract or migration guidance.
  • Add another HA automation to translate plans: a reported workaround in Deye via Solarman: Predbat computes best charge plan but does not apply TOU correctly #3895,
    but adds a separate control owner and is not the native integration requested.
  • Use Deye Cloud: a different transport and capability model; not a substitute
    for local Solarman support.

Additional context

The local combined shadow trial keeps the existing physical controller in charge.
Physical commissioning and general firmware compatibility have not been
established. Passing local tests is not upstream acceptance; the PR remains draft
and its upstream workflow currently requires approval. No private configuration,
credentials, device identifiers or raw household captures are attached.

Activity

  1. springfall2008 commented on Oct 12, 2026

    @springfall2008
    Owner

    🤖 This is an automated first-pass triage — a maintainer will review before any action is taken.

    Classification: enhancement — a feature request for a native, opt-in local Deye/Solarman adapter plus a documented migration path from inverter_type: SK. The ticket reads as the tracking/adoption issue for the design discussion, not a bug report.

    Not a duplicate. No open or closed issue/PR tracks local Solarman/Deye support. #3895 reports the underlying ToU-write problem on an SK-profile setup and stays open separately, as the body itself notes — this ticket is not duplicating it.

    What I checked against current main (d6985b6):

    Related: #3895 (ToU writes not reliably applied over Solarman on SK), #4947 (select-based charge/discharge time entities are not snapped to a valid step size — affects SA/Deye time writes; an in-repo snapper precedent exists in alphaess_const.py's snap_time_grid()), and #4636 (state matches can be echoes of Predbat's own writes — the "observed, not proof" distinction this issue already adopts).

    No priority set, as this is a feature request; no component label applied, as the repo's label set has no Deye/Solarman label.

  2. gcoan commented on Oct 12, 2026

    @gcoan
    Collaborator

    @arturonaredorather than add a native new inverter type for Deye, I suggest it would be better and more flexible to just add support for Deye date/time formats then the inverter can be supported as a custom type (with example apps.ysml and setup instructions), but also that config can be used for any other future inverter.

    Hard coding inverter types in predbat isn't the way we generally extend the inverter pool any more as it locks any fixes into core releases. Using custom inverter types is more flexible

  3. arturonaredo commented on Oct 12, 2026

    @arturonaredo
    Author

    @gcoan Thanks, I agree with the configuration-driven direction. My inverter is a SUN-16K-SG01LP1-EU, connected locally through Home Assistant/Solarman.

    My concern is that “custom” should not mean every user independently maintains their own implementation. Predbat already has both the documented inverter_type + inverter: custom-definition mechanism and a shared templates/ directory. Could we build on those with a reusable, documented Deye/Solarman template maintained in the repository, rather than a collection of private configurations?

    The split I have in mind is:

    • Shared profile/template: capability settings, entity/service mappings and supported time formats for the inverter/integration, with users adapting only installation-specific entities and limits.
    • Generic core support: any missing date/time handling or control primitives, with regression tests, rather than another hardcoded brand-specific path.
    • Explicit compatibility and commissioning notes: supported model/firmware/integration combinations and the checks needed before enabling control. In particular, sharing a template or fixing date parsing must not be presented as proof that six-period ToU/hold behaviour has been physically validated.

    Longer term, I would favour moving the declarative parts of the existing built-in inverter definitions towards the same shared-profile approach, incrementally and preserving existing inverter_type configurations. That need not block this contribution, and vendor-specific protocol/control logic would still require code where appropriate.

    Would a shared Deye/Solarman template plus the smallest necessary generic core changes be the preferred direction for reshaping #5497? My goal is for fixes and improvements to benefit everyone using that integration, not just my installation.

  4. gcoan commented on Oct 12, 2026

    @gcoan
    Collaborator

    5. My concern is that “custom” should not mean every user independently maintains their own implementation. Predbat already has both the documented inverter_type + inverter: custom-definition mechanism and a shared templates/ directory. Could we build on those with a reusable, documented Deye/Solarman template maintained in the repository, rather than a collection of private configurations?

    absolutely, that was what I was thinking of

    Would a shared Deye/Solarman template plus the smallest necessary generic core changes be the preferred direction for reshaping #5497?

    yes please, the smallest set of core changes to enable predbat to talk correctly to your inverter, update the inverter setup 'custom type' documentation to include it, then add a new Deye section to the inverter setup and provide a template for others to use. This is the way we have done a lot of the newer inverter types (Tesla, Luxpower, Sigenergy, Solax, etc)

    Cheers

  5. arturonaredo commented on Oct 12, 2026

    @arturonaredo
    Author

    Implemented the shared-template direction in #5505 and closed the superseded #5497 (its branch is retained). The replacement starts from upstream v9.3.8: a shared Deye/Solarman custom profile, setup/custom-type documentation, and 138 lines of opt-in generic core support for ordered HA-observed service sequences. No new branded core adapter. All 345 registered test groups, all pre-commit hooks and the docs build pass locally. The PR is draft: HA observations are not physical confirmation, and hold/export/power control plus the separate joint-apply compatibility work are explicitly not claimed. No live installation was changed.

  6. arturonaredo commented on Oct 13, 2026

    @arturonaredo
    Author

    Shared-template field evidence — 13 October 2026

    Following the shared custom-profile direction agreed here, #5505 is now operating on my SUN-16K-SG01LP1-EU through local HA/Solarman. This supersedes the initial development-only status; the implementation is the shared YAML plus generic observed service sequences, not the superseded branded adapter in #5497.

    There is HA-observed evidence of both grid charging and demand operation:

    UTC observation Native operation All six ToU rows Reported power
    12 October, 23:01:31 Charging, read-only off Grid, target 59% on every row Grid 3480 W, PV 0 W, house 420 W, battery −2870 W
    13 October, 10:32:37 Demand, read-only off, no reported error; latest cycle 10:30 Disabled, target 10% on every row Grid 0 W, PV 1512 W, house 500 W, battery −913 W

    The earlier accepted command/observation receipt was cross-checked against HA recorder. Battery SOC was 30%, then recorded 31% at 23:04:30 UTC, consistent with grid charging. These power samples are not simultaneous calibrated measurements and do not prove the eventual target was reached.

    At the later check: HA 2026.10.1 / Solarman 26.01.31. The installed generic service-sequence implementation matches public PR head 4546443f by AST comparison; the shared profile and service definitions also match after entity-prefix resolution. The full newly rebased tree was not deployed: this is the earlier combined installation using the same template/control implementation.

    The exact public template head passed 346/346 standalone test groups. I also reran service_sequences, deye_solarman_template and execute: 3/3 groups, no skips. These exercise the real shared YAML/native entrypoints with synthetic HA, including all six rows, ordering, idempotence, failure barriers, retry and Monitor/read-only. Full provenance, test links and reproduction commands are in the existing consolidated PR report.

    Scope of “working”: observed charge/demand operation on this installation. HA observations are not independent hardware acknowledgement or general firmware certification. Hold/freeze, export/power control, outage recovery and physical EV operation remain outside this evidence. No new device actions, configuration changes, restarts or faster polling were used to collect it; no private captures, configuration or identifiers are attached. Upstream CI for this head still needs maintainer approval.

  7. gcoan commented on Oct 14, 2026

    @gcoan
    Collaborator

    @arturonaredo thanks for the PR, I've had a read through, can't comment on the code changes in detail, that will be for Trefor to review, but the shape of what's there looks OK.

    My comments are principally on the documentation:

    • wondered why you had put Deye/Solarman after Sunsynk and before Tesla in the inverter list. I try to keep them in alphabetic order with GivTCP first as that is the Predbat default template
    • you say at the beginning, 'not field commissioned', that confuses me, have you tested this on your own setup?
    • am a bit confused by the table of intent/ordered actions, I assume it is saying the list of commands that Predbat sends to the inverter for different modes, so not sure what "observe all six..." - is that an instruction for the user to verify that that is what happens or is it something Predbat is doing?
    • we use 'SoC' mixed case not 'SOC' in the docs
    • in the Disabled but it describes a set of things that are not enabled or written, I assume you need to tell the user to set these on their inverter manually outside of Predbat?
    • on the charge time about not setting the inverter sensors in apps.yaml, does the user need to manually set the start/end times outside of predbat eg 00:00 and 23:59 so predbat can then control charging?
    • deye commissioning, point 2, don't say 'merge the template into apps.yaml', we try to supply a complete blank template that will cover everything needed, and then the user can configure their energy rates and car details in it so they should replace the default shipped GivTCP template with the deye one. Merging will cause issues I am sure
    • point 4 I don't understand. I think you mean to say that users should disable any other automatic management of the inverter such as Deye cloud
    • "Never select Control charge & discharge with this template." - suggests that this isn't going to work. If we are sharing this then people will expect it to work, even if it is experimental. Not sure what people should do with this statement. Remove?
    • Line 4084 verified service sequences. I think this is missing an intro as to what it is there for, why you would use it, and what the alternative is that has been used before. I assume it is to give predbat the ability to check that a control has been changed as you intended it to, rather than just assuming that the HA command worked (and with repeat: true to force a re-application on each Predbat execution run).
    • Line 4136 your rewrite of the charge_freeze_service behaviour. My understanding per the old doc version is that if charge_freeze_service is not defined and 'switch.enable charge freeze' (or whatever it is called) is enabled then Predbat will use charge_start_service. Your rewrite suggests differently that the battery will go into Demand mode (charge stopped) which is quite different behaviour. TBH I don't really understand the second and third sentences of your rewrite
    • similarly discharge freeze service. There was I recall some discussion about whether these behaviours were logically right, and so your updates may be reflecting what the code actually does
    • since you are changing it, saves me editing it, the 'has_service_api' documentation is wrong, it is actually ignored and can be removed from the documentation (or at least commented that it has no effect setting to true or false). Predbat detects service API's by the presence of (or not) the charge_start_service, charge_stop_service, etc
    • apps.yaml, can you expand this to a full template so people can install it directly, add the car charging, energy rates, etc, just copy from the standard apps.yaml template
    • in the template you have what appear to be labels, e.g. " - &disable_sources" - this isn't I think covered in the inverter setup documentation
    • I don't recognise what this would do? Is this a subroutine that can be called eg from charge_stop_service?
      - <<: *disable_sources
          option: "Grid"
    

    sorry there is a lot of comments, it looks good work, the introduction of explicit verify of config is a good idea and a useful addition. My main feeling is you need to make it more user-friendly the doc, easier for new users to read and understand what is happening

    Cheers

  8. arturonaredo commented on Oct 14, 2026

    @arturonaredo
    Author

    Thank you for the detailed review @gcoan !! Let me elaborate a response for you!

  9. arturonaredo commented on Oct 14, 2026

    @arturonaredo
    Author

    Thanks again @gcoan for the detailed documentation review. I have addressed the points below in 17 separate commits on #5505, including a Quick start. This update changes the documentation, example configuration and its regression assertions; it does not change the inverter's runtime service routing.

    1. Inverter list order

    I try to keep them in alphabetic order with GivTCP first

    Moved Deye/Solarman alongside DEYE Cloud in the alphabetical list, leaving GivTCP first. Commit f2d5ad0.

    2. Testing on my installation

    'not field commissioned' ... have you tested this on your own setup?

    Yes: grid charging and normal self-consumption have been used on my SUN-16K-SG01LP1-EU through local Solarman, with HA observations and recorded telemetry. I replaced the confusing blanket statement with that evidence and its scope. I am not claiming validation of every Deye model/firmware or failure recovery. Commit 5f7b075.

    3. Commands versus observations

    not sure what "observe all six..." ... is it something Predbat is doing?

    Both are automatic Predbat operations. The table now separates what Predbat sends from what it checks in HA. It disables the six sources, checks them, sets/checks the six targets, then enables/checks Grid. A failed phase stops the remaining sequence. All programs receive the current command because the inverter selects its active program by time; this is not six future forecast slots. Commit 4aee8e0.

    4. SoC spelling

    we use 'SoC' mixed case not 'SOC' in the docs

    Changed the Deye prose and template comments to SoC, without renaming actual entity IDs or configuration keys. Commit 227bbdb.

    5. Disabled and manual prerequisites

    you need to tell the user to set these on their inverter manually outside of Predbat?

    Separated Charging sources and required inverter setup from the automatic command table. Disabled disables that program's grid/generator charging source, not the inverter or all battery activity. The documentation explicitly lists the work mode, ToU, Program Power/current and protection settings the user must configure or verify outside Predbat. It does not prescribe universal battery/BMS limits. Commit 74951bb.

    6. Physical time settings

    does the user need to manually set the start/end times outside of predbat eg 00:00 and 23:59

    The current template requires an enabled six-program schedule covering the complete day, including the overnight wrap. These are six physical boundaries, not one 00:00–23:59 start/end pair. The user configures/checks them on the inverter or through Solarman; Predbat's start/end sensors are internal bookkeeping and must not be mapped onto two of those six controls.

    Solarman exposes writable time entities, but this template does not initialise them, and the verified sequence implementation currently does not support time.set_value. Automatic initialisation would need a separately implemented/tested extension. Commit 3cfb1ca.

    7. Replace rather than merge

    don't say 'merge the template into apps.yaml'

    Changed the instructions to back up the existing file, replace the shipped GivTCP example with the complete Deye template, and configure the user's rates/forecasts/car there. The instructions explicitly say not to combine inverter profiles. Commit 3788df2.

    8. Other automatic controllers

    users should disable any other automatic management of the inverter such as Deye cloud

    That is now stated directly. Other automatic writers must be disabled before enabling Predbat control; monitoring-only readers are distinguished from competing controllers. The template does not disable those systems itself. Commit df59097.

    9. Control charge and discharge

    "Never select Control charge & discharge with this template." ... Remove?

    Replaced the prohibition with the supported mode and reason: Control charge supports grid charging and normal discharge to household loads. Scheduled forced export is not implemented by this template. Selecting the additional mode still uses the same profile, but does not add a missing discharge-start/export-control capability. I have not removed the limitation or claimed forced export works. Commit 2209b14.

    10. Verified service sequences

    missing an intro ... why you would use it, and what the alternative is

    Added the motivation and a comparison with traditional service templates. repeat: true resends traditional calls but does not verify state. Verified sequences check observed final values on each invocation, avoid unnecessary writes and wait between changed steps. repeat/always are not accepted in verified entries. HA read-back remains an observation, not independent hardware confirmation. Commit 6f1329f.

    11. Charge freeze fallback

    if charge_freeze_service is not defined ... Predbat will use charge_start_service

    I checked both the v9.4.0 upstream implementation and its tests. The distinction is:

    Situation with no charge freeze hook Existing fallback
    Explicit freeze request with a positive target charge_stop_service
    Target equals current SoC, without an explicit freeze request charge_start_service

    The docs now explain both cases, rather than implying one universal fallback. These runtime methods are unchanged from upstream by this PR. Stopping charging alone is not a guarantee of a physical battery hold. Commit cee5be6.

    12. Discharge freeze fallback

    similarly discharge freeze service ... reflecting what the code actually does

    Confirmed against the same upstream code/tests: an explicit discharge freeze first stops charging, then uses the freeze hook or discharge_stop_service when that hook is absent. Ordinary export reaching its target stops discharge without invoking a freeze. The docs also distinguish absent hooks from configured empty lists and explain the separate idle-export stop fallback. No routing behaviour was changed. Commit 4de6ca3.

    13. has_service_api

    it is actually ignored and can be removed from the documentation

    Confirmed that the Python implementation does not consult this flag. Removed it from the new template and custom-profile example, and retained a short compatibility note explaining that True/False has no effect: the configured service hooks determine the service calls. Commit f5b4fa0.

    14. Complete apps.yaml template

    expand this to a full template ... add the car charging, energy rates, etc

    Expanded the file with currency, hybrid modelling, load-history/horizon/scaling settings, optional PV forecast and rate examples, optional per-car inputs, notifications and watch-list examples based on the standard configuration. template: true remains, cars default to zero, and no other inverter/controller is activated. The user still needs to supply actual entities, tariffs and installed limits. Added regression assertions for the complete blank template. Commit 7adf0e2.

    15. YAML anchors

    what appear to be labels, e.g. "- &disable_sources"

    Added an explanation: &disable_sources names a YAML mapping; *disable_sources reuses it. The anchored entry is still a real step in its original list. This is resolved during YAML loading, not a Predbat subroutine. Commit 4fa29be.

    16. YAML merge

    <<: *disable_sources ... option: "Grid"

    Added its fully expanded equivalent. << reuses the service/entity/verification fields, while the explicit option: "Grid" replaces Disabled. The resulting step enables Grid; it does not call a separate disable routine. Commit 6efbafe.

    17. Easier first-time setup

    make it more user-friendly ... easier for new users to read and understand

    Added a Quick start before the detailed explanation: Solarman, replacing the default template, configuring rates/forecasts/car inputs, preparing the inverter, removing competing writers, then Monitor and a checked Control charge cycle. The detailed limitations and service reference remain available below it. Commit eff7231.

    Validation

    • Exact Add shared Deye/Solarman template with observed service sequences #5505 head: 347/347 registered test groups passed, with a freshly built native kernel and no skips.
    • Local combination with the current joint-planning and diagnostics changes: 371/371 groups passed, with the shared template required and no skips.
    • Repository pre-commit checks pass. MkDocs builds; its warning/anchor messages match the pre-change baseline, with no new warnings.
    • The existing source/target service mappings are preserved after YAML expansion, apart from removing the unused flag. No new physical-time or protection-setting writes were introduced, and this documentation review was not deployed to my home system.

    These checks do not extend the one-installation field evidence to other inverter models, forced export or outage recovery. Current-head upstream CI run 38654234995 reports action_required and awaits maintainer approval; local tests are not an upstream CI pass.

    I hope this way of giving you a reply helps!

  10. gcoan commented on Oct 14, 2026

    @gcoan
    Collaborator

    thanks for your commits and extensive replies, I'll take a fresh look at the draft PR

    yaml anchors, never seen them before. Learn something new

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BOT_TRIAGEDHas been through the triage botenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions