diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5f46e5f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,433 @@
+# anker-shelly-bridge
+
+
+
+
+
+Automate a Shelly smart plug from live Anker SOLIX telemetry.
+
+Your SOLIX device reports battery level, solar input, and load over Anker's
+cloud MQTT service. This reads that telemetry and switches a Shelly plug on
+your local network according to rules you write in a plain text file.
+
+The common use is controlling grid charging: plug the SOLIX into a Shelly, and
+let the battery level decide when to draw from the wall.
+
+**The SOLIX device is read-only.** This tool never sends it a command. The
+Shelly plug is the only thing it ever switches.
+
+> Unofficial and unaffiliated with Anker or Allterco Robotics. SOLIX and Shelly
+> are trademarks of their respective owners. Built on the community
+> [anker-solix-api](https://github.com/thomluther/anker-solix-api) library.
+
+---
+
+## Quick start
+
+You need a SOLIX device that connects to WiFi, a Shelly plug on the same
+network, and your Anker account login.
+
+```bash
+git clone https://github.com/YOURNAME/anker-shelly-bridge.git
+cd anker-shelly-bridge
+./start.sh
+```
+
+On Windows, double-click `start.bat`.
+
+That is the whole install. `start.sh` creates its own Python environment,
+installs everything, and hands over to a guided setup with eight steps:
+
+1. **Dependencies**: installs whatever is missing
+2. **Anker account**: your login, stored locally with owner-only permissions
+3. **Find your SOLIX device**: connects and captures every field it reports
+4. **Find your Shelly plug**: scans the local network
+5. **Check the plug**: finds schedules and timers already on it that would
+ conflict, and offers to remove them
+6. **Notifications**: optional push to your phone, with a QR code to scan
+7. **Rules**: pick a strategy and answer a few questions in plain language
+8. **Test, then start**: a live dry run against your hardware that switches
+ nothing, then offers to install a background service
+
+Nothing touches your hardware until step 8 asks. Ctrl-C is safe at any point.
+
+Needs Python 3.12+ and git. If they are missing, `start.sh` tells you how to
+install them for your platform.
+
+---
+
+## What it does
+
+### Reads your SOLIX device
+
+Connects to Anker's cloud MQTT broker, captures a live telemetry snapshot, and
+writes a device profile you can read. A portable power station typically
+reports around 44 fields: battery percentage, per-string solar input, AC and DC
+output, temperature, port states.
+
+It also computes derived fields, so rules can use `pv_total` instead of adding
+`pv_1_power` and `pv_2_power` by hand:
+
+| Field | Meaning |
+|---|---|
+| `pv_total` | all solar strings added together, in watts |
+| `pv_surplus` | solar minus load; positive means the surplus is charging the battery |
+| `pv_covers_load` | true when solar alone is carrying everything |
+| `usb_total` | combined USB output |
+| `soc_headroom` | percentage points above the configured floor |
+
+```bash
+solixauto fields # every usable field name
+solixauto status --watch # live values
+```
+
+### Controls your Shelly plug
+
+Local HTTP only, no cloud. Gen1 and Gen2+ including Gen4. Discovery uses mDNS
+plus a subnet scan across every private network it can see, so machines with
+several interfaces work.
+
+```bash
+solixauto switch on|off|status
+```
+
+Every command reads the state back from the device afterwards rather than
+trusting the HTTP response.
+
+### Runs your rules
+
+A power profile is a YAML file linking one SOLIX device to one Shelly channel:
+
+```yaml
+rules:
+ - name: top up from grid when low
+ when: battery_soc <= 35
+ for: 2m
+ then: target.on
+
+ - name: stop charging when full enough
+ when: battery_soc >= 85
+ for: 2m
+ then: target.off
+```
+
+`when` is an expression over any field the device reports. `for` is how long
+the condition must hold before anything happens, so a passing cloud or a
+momentary load spike cannot toggle the relay. `priority` breaks ties when rules
+disagree.
+
+Expressions run in a sandbox allowing only comparisons, `and`/`or`/`not`, and
+arithmetic. Function calls and attribute access are rejected at parse time, so
+a power profile cannot execute code.
+
+Full rule reference with worked examples: [docs/RULES.md](docs/RULES.md).
+The same document is written into your data directory during setup.
+
+---
+
+## Live monitor
+
+```bash
+solixauto monitor
+```
+
+Opens a dashboard at `http://127.0.0.1:8765` showing every device you have
+saved: battery level, solar in, grid in, load out, and each Shelly's switch
+state and draw. It refreshes every five seconds and keeps a rolling chart.
+
+Each device gets a **power bus**: solar and grid drawn from the left, load
+from the right, all to one scale. If the left outweighs the right, the battery
+is filling. Light and dark themes, remembered between visits.
+
+Add `--host 0.0.0.0` to reach it from a phone on the same network.
+
+Anker readings come from a running automation rather than a second cloud
+connection, so start a service first. Two MQTT sessions on one Anker account
+invite rate limiting. Shelly devices are polled directly over local HTTP and
+always show live.
+
+---
+
+## Safety
+
+Controlling the power supply to a battery has a specific failure mode: turn
+charging off, let the battery run flat, and the device drops off the network,
+at which point nothing can turn charging back on. The design is built around
+preventing that.
+
+### The battery floor
+
+```yaml
+safety:
+ battery_floor:
+ at_or_below: 20
+ release_at: 40
+ then: target.on
+```
+
+Checked before any rule. It **bypasses the rate limits**, **outranks every
+rule**, and **latches** once tripped, so nothing can turn the plug off again
+until the battery reaches `release_at`. Without the latch, a solar rule could
+release it at 21% straight back into whatever drained it.
+
+`release_at` must be meaningfully above `at_or_below`; the profile is rejected
+otherwise.
+
+### Failing in the safe direction
+
+```yaml
+source:
+ stale_after: 300s
+ on_stale: safe_state
+safe_state: on
+```
+
+If telemetry stops arriving, rules are never evaluated against stale values.
+`hold` leaves the plug alone, `safe_state` drives it to a known state, `stop`
+exits. When the plug supplies power to the SOLIX device, `safe_state: on` means
+losing sight of it fails toward charging.
+
+Rules are also never evaluated against **partial** telemetry. If a field a rule
+needs has not arrived yet, nothing is evaluated at all, including the floor.
+
+### Rate limits
+
+```yaml
+limits:
+ min_seconds_between_actions: 60
+ max_actions_per_hour: 20
+```
+
+A hard backstop independent of dwell times. If a rule somehow oscillates, this
+caps the damage. The battery floor deliberately ignores it.
+
+### Conflict detection
+
+A Shelly can hold schedules, auto-on/auto-off timers, and webhooks on the
+device itself. They run whether or not this tool is running, and they silently
+override it.
+
+```bash
+solixauto conflicts # list them
+solixauto conflicts --fix # remove them, asking before each change
+```
+
+Checked at discovery, at `--test`, and again at engine startup.
+
+One limitation: schedules created as Shelly Cloud **scenes** live in the cloud
+rather than on the device and cannot be seen over local HTTP. If behaviour
+still looks wrong after `conflicts` is clean, check the app's scenes.
+
+---
+
+## Testing before you trust it
+
+```bash
+solixauto run --test
+```
+
+Validates syntax, checks every field name against what the device actually
+reports, warns about missing deadbands and short dwell times, connects to both
+devices, and prints what each rule would do right now. Switches nothing.
+
+```bash
+solixauto run --test --offline
+```
+
+Same checks without connecting, evaluated against values captured at discovery.
+
+```bash
+solixauto run --test --simulate battery_soc=12
+```
+
+Force a rule to fire without waiting for real conditions. Prove your
+low-battery logic works at 2pm on a sunny day, and see the exact notification
+text it would send.
+
+```bash
+solixauto run --dry-run
+```
+
+The full engine loop with real telemetry, narrating every cycle, but no switch
+command and no notification.
+
+---
+
+## Notifications
+
+```bash
+solixauto notify-setup
+```
+
+Interactive: pick a channel, it configures and tests it. For ntfy it generates
+a random private topic, shows QR codes for the app store and the topic, and
+sends a test push.
+
+Supported: **ntfy** (free, no account), **Pushover**, **email**, **Telegram**,
+**webhook** (Slack/Discord/custom), and **desktop** (osascript on macOS,
+notify-send on Linux, PowerShell on Windows).
+
+Credentials live in `notifications.yaml` with owner-only permissions, never in
+power profiles, so profiles stay safe to share.
+
+Battery floor alerts fire **even when notifications are otherwise disabled**,
+at elevated priority, bypassing the throttle. Muting routine chatter should not
+silence a battery emergency.
+
+The Anker app and the Shelly app cannot receive custom push messages from an
+external program, so neither is an option.
+
+---
+
+## Running it unattended
+
+```bash
+solixauto service # install and start
+solixauto service --status
+solixauto service --uninstall
+```
+
+macOS gets a LaunchAgent, Linux a systemd user unit, both starting at login and
+restarting on crash. Windows prints the Task Scheduler command.
+
+If the machine sleeps, the automation sleeps with it and the safety floor
+cannot protect anything. Use an always-on machine, or disable sleep.
+
+---
+
+## Layout
+
+Code lives where you cloned it. Everything else lives in `~/solix-automation`:
+
+```
+~/solix-automation/
+├── venv/ Python environment created by start.sh
+├── device-profiles/
+│ ├── anker/ what your SOLIX device reports
+│ └── shelly/ your plugs and their capabilities
+├── power-profiles/ your rules, hand-editable
+│ └── README.md full rule reference with worked examples
+├── notifications.yaml channel credentials, mode 0600
+├── state/runtime.json last known target state
+└── logs/automation.log every action taken
+```
+
+Override the root with `SOLIXAUTO_HOME`.
+
+---
+
+## Commands
+
+```
+solixauto setup guided setup, start here
+solixauto doctor check this machine is set up correctly
+
+solixauto discover-anker find and profile SOLIX devices
+solixauto discover-shelly find and profile Shelly devices
+solixauto devices list saved device profiles
+solixauto name "" name a device, rename its file
+solixauto fields field names usable in rules
+solixauto status live telemetry
+solixauto switch on|off manual control
+solixauto conflicts automation set on the plug itself
+solixauto monitor live dashboard in your browser
+
+solixauto new-profile scaffold a power profile
+solixauto profiles list power profiles
+solixauto validate check without connecting
+solixauto run --test test against real devices, switch nothing
+solixauto run run it
+
+solixauto notify-setup configure push notifications
+solixauto notify-test send a test
+solixauto notify-qr show the ntfy topic QR again
+
+solixauto service run in the background at login
+```
+
+Profiles resolve by friendly name, serial, ID, MAC, or IP, so all of these
+reach the same device:
+
+```bash
+solixauto switch "Garage Plug" on
+solixauto switch 192.168.1.50 on
+solixauto switch garage-plug on
+```
+
+---
+
+## Device support
+
+Anything the upstream
+[anker-solix-api](https://github.com/thomluther/anker-solix-api) library
+supports **and** that holds a cloud connection.
+
+Models that pair with the Anker app over Bluetooth only, where you press a
+button on the unit to make it discoverable, publish nothing to the MQTT broker
+and cannot be used. The F2000 / PowerHouse 767 works this way. Discovery detects and skips
+them.
+
+Shelly Gen1 and Gen2+ including Gen4, over local HTTP.
+
+Developed against a SOLIX F3000 (A1782) and a Shelly Plug US Gen4. Other
+combinations should work; reports welcome.
+
+---
+
+## Known limitations
+
+- Field mappings come from a community reverse-engineering effort, not from
+ Anker. Fields ending in `?` or starting with `unknown_` are unconfirmed, so
+ do not build rules on them.
+- **Verify any field against the Anker app before trusting it.** The solar
+ fields in particular should be watched in daylight and compared to the app
+ before writing solar rules.
+- Shelly Cloud scenes and app-set device names are invisible over local HTTP.
+- Requires a machine that stays awake.
+- Anker rate-limits logins; avoid restarting the service in a tight loop.
+
+---
+
+## Troubleshooting
+
+**A device reports no telemetry.** It is powered off, asleep, off WiFi, or
+Bluetooth-only. Confirm it shows online in the Anker app, then retry that
+device alone with `--sn `.
+
+**Shelly discovery finds nothing.** Try `--host 192.168.1.50` or
+`--network 192.168.1.0/24`. Give your plugs DHCP reservations; `access.host` is
+a fixed address in the profile.
+
+**The automation does nothing.** Check `solixauto service --status`
+and the log. Rules only act after their `for:` dwell has fully elapsed.
+
+**Something switches the plug unexpectedly.** Run `solixauto conflicts `,
+then check the Shelly app for cloud scenes.
+
+**Anything else.** `solixauto doctor` reports platform, dependencies,
+credentials, network, and notification status in one place.
+
+---
+
+## Documentation
+
+- [docs/RULES.md](docs/RULES.md): power profile format, every option, worked
+ automation examples
+- [docs/TESTING.md](docs/TESTING.md): staged checklist for validating a new
+ setup before trusting it with real hardware
+- [examples/](examples/): a solar failover profile and an annotated
+ notifications config
+
+## Contributing
+
+Bug reports welcome, particularly for device models not listed above. Include
+the output of `solixauto doctor` and the relevant section of
+`logs/automation.log`.
+
+**Never paste `notifications.yaml`, your `.env`, or an ntfy topic** into an
+issue. Device profiles contain serial numbers; redact them if that matters to
+you.
+
+## License
+
+MIT. See [LICENSE](LICENSE).
diff --git a/screenshot.jpg b/screenshot.jpg
new file mode 100644
index 0000000..625daa2
Binary files /dev/null and b/screenshot.jpg differ