233 lines
6.6 KiB
Markdown
233 lines
6.6 KiB
Markdown
# Power profiles
|
|
|
|
A power profile is a plain YAML file linking one Anker SOLIX device to one
|
|
Shelly switch channel. You can edit it in any text editor.
|
|
|
|
The Anker device is **read-only**. The engine reads its telemetry and never
|
|
sends it a command. The only thing that gets switched is the Shelly.
|
|
|
|
## Layout
|
|
|
|
device-profiles/anker/ generated, one file per Anker device
|
|
device-profiles/shelly/ generated, one file per Shelly device
|
|
power-profiles/ yours, hand-edited
|
|
state/runtime.json last known target state per profile
|
|
logs/automation.log action history
|
|
|
|
## Workflow
|
|
|
|
solixauto discover-anker
|
|
solixauto discover-shelly
|
|
solixauto new-profile solar-failover --template solar
|
|
solixauto fields A1782-<serial>
|
|
solixauto run solar-failover --test
|
|
solixauto run solar-failover
|
|
|
|
## Anatomy of a rule
|
|
|
|
- name: grid assist when solar drops
|
|
when: pv_total < 150
|
|
for: 90s
|
|
then: target.on
|
|
priority: 0
|
|
|
|
`when` is an expression over any field listed in the Anker device profile,
|
|
under `readable` or `derived`. `solixauto fields <device>` prints them with
|
|
current sample values.
|
|
|
|
`for` is the dwell time. The condition must stay true for this long before
|
|
anything happens. Without it, a cloud passing over your array would cycle the
|
|
relay repeatedly.
|
|
|
|
`then` is `target.on`, `target.off`, or `none`.
|
|
|
|
`priority` breaks ties. If two rules are ready at the same moment and disagree,
|
|
the higher number wins. A low-battery override should outrank normal solar
|
|
logic.
|
|
|
|
## Use a deadband
|
|
|
|
This is the single most important thing to get right:
|
|
|
|
# WRONG - will chatter around 200W
|
|
- when: pv_total < 200
|
|
then: target.on
|
|
- when: pv_total > 200
|
|
then: target.off
|
|
|
|
# RIGHT - 150W of deadband between the two
|
|
- when: pv_total < 150
|
|
then: target.on
|
|
- when: pv_total > 300
|
|
then: target.off
|
|
|
|
`--test` warns when it detects the same threshold used for both directions.
|
|
|
|
## Useful automations
|
|
|
|
**Solar failover.** Solar covers the load most of the day; pull from the wall
|
|
only when production drops.
|
|
|
|
- name: grid assist when solar drops
|
|
when: pv_total < 150
|
|
for: 90s
|
|
then: target.on
|
|
|
|
- name: release grid when solar recovers
|
|
when: pv_total > 300
|
|
for: 2m
|
|
then: target.off
|
|
|
|
**Low-battery charge.** No solar involved.
|
|
|
|
- name: charge when battery is low
|
|
when: battery_soc <= 15
|
|
for: 30s
|
|
then: target.on
|
|
|
|
- name: stop charging when battery is healthy
|
|
when: battery_soc >= 60
|
|
for: 2m
|
|
then: target.off
|
|
|
|
**Overnight top-up.** Combine conditions.
|
|
|
|
- name: cheap overnight charging
|
|
when: battery_soc < 80 and pv_total < 20
|
|
for: 5m
|
|
then: target.on
|
|
|
|
**Load shedding.** Cut a non-essential circuit when the battery is draining.
|
|
|
|
- name: shed load
|
|
when: battery_soc < 30 and ac_input_power == 0
|
|
for: 2m
|
|
then: target.off
|
|
|
|
**Thermal guard.** Higher priority so it outranks everything else.
|
|
|
|
- name: stop charging when hot
|
|
when: temperature >= 45
|
|
for: 60s
|
|
then: target.off
|
|
priority: 200
|
|
|
|
## Safety settings
|
|
|
|
`stale_after` and `on_stale` control what happens when telemetry stops
|
|
arriving. Rules are never evaluated against stale data.
|
|
|
|
- `hold` keeps the relay wherever it is. Default and safest.
|
|
- `safe_state` drives the relay to the `safe_state:` value.
|
|
- `stop` exits the engine.
|
|
|
|
`limits` is a hard backstop independent of dwell times:
|
|
|
|
limits:
|
|
min_seconds_between_actions: 60
|
|
max_actions_per_hour: 20
|
|
|
|
If a rule somehow oscillates, this caps the damage.
|
|
|
|
## Notifications
|
|
|
|
Turn them on in the profile:
|
|
|
|
notifications:
|
|
enabled: true
|
|
channels: [ntfy]
|
|
title: "{profile}"
|
|
template: >-
|
|
{source_name} battery {battery_soc}%, solar {pv_total}W.
|
|
{target_name} turned {action}.
|
|
throttle: 5m
|
|
on:
|
|
- action
|
|
|
|
Then per rule, `notify: on` or `notify: off` to include or exclude it. Omit it
|
|
to inherit. A rule can also carry its own wording:
|
|
|
|
- name: emergency charge on low battery
|
|
when: battery_soc <= 15
|
|
for: 30s
|
|
then: target.on
|
|
priority: 100
|
|
notify:
|
|
template: >-
|
|
{source_name} has {battery_soc}% battery remaining.
|
|
{target_name} turned on AC power.
|
|
priority: high
|
|
|
|
### Template fields
|
|
|
|
Any field from the device profile works, plus:
|
|
|
|
{profile} power profile name
|
|
{rule} rule that fired
|
|
{condition} the rule's when expression
|
|
{action} ON or OFF
|
|
{action_word} on or off
|
|
{source_name} Anker device name, falling back to model
|
|
{source_model} e.g. SOLIX F3000
|
|
{source_serial}
|
|
{target_name} Shelly device name, falling back to model
|
|
{target_model}
|
|
{target_host}
|
|
{time}
|
|
|
|
`--test` checks every field name in your templates against the device profile,
|
|
so a typo is caught before it ships a message reading `battery ?%`.
|
|
|
|
### Channels
|
|
|
|
Credentials live in `../notifications.yaml`, which is created with owner-only
|
|
permissions. Power profiles stay free of secrets.
|
|
|
|
- **ntfy** - recommended. Free, no account. Install the app, pick an
|
|
unguessable topic name, subscribe. Anyone who knows the topic can read your
|
|
alerts, so make it long.
|
|
- **pushover** - $5 once per platform. Priority 2 alerts repeat until you
|
|
acknowledge them.
|
|
- **email** - SMTP. Gmail requires an App Password.
|
|
- **telegram** - free bot.
|
|
- **webhook** - Slack, Discord, or generic JSON.
|
|
- **desktop** - local notification on the machine running the engine.
|
|
Uses osascript on macOS, notify-send on Linux, PowerShell on Windows.
|
|
Run `solixauto doctor` to see which backend was detected.
|
|
|
|
The Anker app and the Shelly app cannot receive custom push messages from an
|
|
external program, so neither is an option here.
|
|
|
|
Test a channel:
|
|
|
|
solixauto notify-test
|
|
solixauto notify-test --channel ntfy
|
|
|
|
### Throttling
|
|
|
|
`throttle` is per rule. An identical repeated message inside the window is
|
|
dropped. This is separate from the switching rate limits, so a stuck condition
|
|
cannot flood your phone even if the relay is behaving.
|
|
|
|
### Other events
|
|
|
|
on:
|
|
- action
|
|
- stale
|
|
|
|
`stale` fires once when telemetry stops arriving and is worth enabling if you
|
|
depend on the automation.
|
|
|
|
## Testing
|
|
|
|
solixauto run <profile> --test
|
|
|
|
Validates syntax, checks that every field you reference actually exists on the
|
|
device, warns about missing deadbands and short dwell times, connects to both
|
|
devices, and prints what each rule would do right now. Nothing is switched.
|
|
|
|
solixauto run <profile> --test --offline
|
|
|
|
Same checks without connecting. Rules are evaluated against the sample values
|
|
captured during discovery.
|