Monitor and control EG4 solar inverters, GridBOSS, and batteries in Home Assistant over local Modbus, WiFi dongle, serial, cloud API, or hybrid connectivity.
This integration connects your EG4 solar equipment to Home Assistant so you can see real-time production, battery, and grid data, control charging and operating modes, and build automations around your energy system. It works with the EG4 cloud account you already use, or directly against your hardware over Modbus for fast, internet-free local polling. No technical knowledge of solar systems is required — if you can use the EG4 Monitor app, you can use this integration.
- Local & cloud connectivity: Modbus TCP, WiFi dongle, USB/RS485 serial, cloud API, or hybrid mode.
- Broad device support: FlexBOSS21, FlexBOSS18, 18kPV, 12kPV, XP inverters, LXP-EU (three-phase), LXP-LB-BR (Brazil 10kW), GridBOSS, and individual batteries.
- Real-time monitoring: power, voltage, current, temperature, frequency, and energy statistics with split-phase per-leg detail.
- Fast local polling: 5-second updates over Modbus, dongle, or serial — no internet dependency.
- Hybrid mode: enrich local data with cloud-only features such as DST auto-sync, and fall back to the cloud for control writes when the local link is down.
- Data integrity: WiFi dongle cross-request validation, canary checks, and energy monotonicity guards protect against corrupt readings.
- Control & automation: quick charge, battery backup (EPS), operating modes, SOC limits, charge/discharge currents, and GridBOSS smart port configuration.
- BMS diagnostics: bank-level cell voltage, temperature, current limits, and cycle count — always available, no CAN bus needed.
- Battery tracking: round-robin battery cache with per-battery last-seen timestamps for systems with more than four batteries.
- Multi-station support: monitor multiple solar installations from one account.
- Multi-language support: 12 languages (Chinese Simplified, Chinese Traditional, Dutch, French, German, Italian, Japanese, Korean, Polish, Portuguese, Russian, Spanish).
- EG4 solar equipment: at least one EG4 inverter (FlexBOSS, 18kPV, 12kPV, XP) or GridBOSS device.
- A connection method (at least one):
- Cloud: an active account on monitor.eg4electronics.com.
- Local Modbus TCP: an RS485-to-Ethernet adapter (e.g. Waveshare) wired to your inverter.
- Serial Modbus (USB/RS485): a USB-to-RS485 adapter on your Home Assistant host.
- WiFi dongle: direct network access to your inverter's WiFi dongle.
- Home Assistant 2026.1.0 or newer.
- HACS (recommended) for easy installation and updates.
See INSTALL.md for the complete guide.
Quick version (HACS): add this repository as a custom repository in HACS, install EG4 Web Monitor, restart Home Assistant, then add the integration from Settings → Devices & Services.
| Connection type | Description | Update speed | Internet required |
|---|---|---|---|
| Cloud API (HTTP) | Connect via EG4's cloud service | 30 seconds | Yes |
| Local Modbus TCP | Direct RS485 connection via adapter | 5 seconds | No |
| WiFi dongle | Direct connection via the inverter's WiFi dongle | 5 seconds | No |
| Serial Modbus (USB/RS485) | Direct USB-to-RS485 serial connection | 5 seconds | No |
| Hybrid | Local polling + cloud for DST sync & quick charge | 5 seconds | Yes (cloud features) |
The connection type is derived automatically from what you configure: cloud credentials only → HTTP mode; local devices only → Local mode; both → Hybrid mode. See docs/CONFIGURATION.md for the full setup walkthrough, including Waveshare RS485 wiring and adapter settings, serial and WiFi dongle setup, options (refresh intervals), and reconfiguration.
- Go to Settings → Devices & Services → Add Integration.
- Search for EG4 Web Monitor and select it.
- Choose a starting point:
- Cloud (HTTP): enter your EG4 Monitor credentials and select a station; optionally add a local device to create a hybrid connection.
- Local Device: pick Modbus TCP, WiFi Dongle, or Serial (USB/RS485) and enter the connection details — the model and serial number are auto-detected.
If you switch to a different station/plant during reconfiguration, entity IDs change to reflect the new station's devices, and automations or dashboards that reference the old IDs need updating. Changing only credentials for the same station leaves entity IDs unchanged.
- Inverters: FlexBOSS21, FlexBOSS18, 18kPV, 12kPV, XP series, LXP-EU (three-phase), LXP-LB-BR (Brazil 10kW).
- GridBOSS: microgrid interconnection devices with smart port configuration.
- Batteries: all EG4-compatible battery modules with BMS integration and individual cell monitoring.
The integration exposes switches (quick charge, battery backup/EPS, DST, working
modes), selects (operating mode, GridBOSS smart port modes, battery charge/discharge
control mode), numbers (SOC and voltage limits, AC/PV charge power, charge/discharge
currents, PV start voltage, peak shaving), and a refresh-data button, plus a
eg4_web_monitor.refresh_data service action. Batteries can be regulated by SOC
(default) or Voltage — see
Battery control mode
for the SOC-vs-Voltage limits and the EG4-label cross-reference (e.g. EG4's
"Back Up Volt(V)" = the AC Charge End Voltage entity). The full entity and
control catalog is documented in
docs/CONFIGURATION.md, and every register-to-sensor and
API-to-sensor mapping is in docs/DATA_MAPPING.md.
If you install the integration on an existing EG4 system, Home Assistant only
has energy history from the install date forward. The
eg4_web_monitor.import_historical_data service backfills plant-level daily
energy history from the EG4 cloud into Home Assistant long-term statistics:
PV yield, consumption, grid import, grid export, battery charge, and battery
discharge (whichever of these the cloud returns for your system).
action: eg4_web_monitor.import_historical_data
data:
config_entry: YOUR_CONFIG_ENTRY_ID # pick the plant in the UI selector
start_date: "2024-01-01"
end_date: "2024-12-31" # optional, defaults to today
dry_run: true # preview first — no data is written
response_variable: import_resultHow it behaves:
- Separate statistics, not sensor history. Data is written as external
statistics with IDs like
eg4_web_monitor:plant_12345_yield. These can never collide with (or modify) your live sensors' recorded history. To use them, open Settings → Dashboards → Energy and select the imported statistics as additional sources, or chart them with any statistics card. - Daily resolution. One value per day, placed at local midnight. Hourly views of the Energy dashboard show the whole day in the first hour; daily, monthly, and yearly views are accurate. Because the EG4 cloud reports station timezones as fixed offsets (e.g. "GMT -8") without DST rules, day boundaries use Home Assistant's configured timezone (your HA instance normally lives at the plant); a genuine IANA station timezone is honored as-is.
- Idempotent. Re-running the same or overlapping ranges does not double count — rows are overwritten and cumulative sums are recomputed from the earliest imported day.
- Bounded and opt-in. Requires cloud credentials (Cloud or Hybrid mode), a maximum range of 2 years per call (run multiple calls for older history), and roughly one cloud request per month per inverter/parallel group.
- Dry run. With
dry_run: truethe service fetches and reports what it would import (per-series day counts and kWh totals) without writing anything. The service returns a summary as response data either way.
automation:
- alias: "Charge Batteries During Off-Peak"
trigger:
- platform: time
at: "23:00:00"
action:
- service: switch.turn_on
target:
entity_id: switch.18kpv_1234567890_quick_charge
- alias: "Stop Quick Charge at Peak Hours"
trigger:
- platform: time
at: "07:00:00"
action:
- service: switch.turn_off
target:
entity_id: switch.18kpv_1234567890_quick_chargeautomation:
- alias: "Low Battery Notification"
trigger:
- platform: numeric_state
entity_id: sensor.18kpv_1234567890_state_of_charge
below: 20
action:
- service: notify.mobile_app
data:
message: "Battery level is low ({{ states('sensor.18kpv_1234567890_state_of_charge') }}%)"
title: "Solar Battery Alert"automation:
- alias: "Enable EPS on Grid Failure"
trigger:
- platform: numeric_state
entity_id: sensor.18kpv_1234567890_grid_power
below: 0.1
for:
minutes: 5
action:
- service: switch.turn_on
target:
entity_id: switch.18kpv_1234567890_battery_backupInverters expose an AC Couple switch plus AC Couple Start SOC and
AC Couple End SOC number entities. The switch toggles the AC couple
function itself (FUNC_AC_COUPLING_FUNCTION) — off means the AC-coupled
source on the smart port is de-energized at any battery level (#471). The
SOC window governs the function while it is enabled: the source is enabled
when battery SOC drops below Start and disabled above End (#352).
Scripting these lets you de-energize the smart port on demand — e.g. to
safely transfer a grid-tied inverter between the grid and the smart port.
The parameters are not family-specific: they are used live on off-grid
12000XP systems and on-grid hybrid LXP systems alike.
Notes:
- Cloud-only: the portal parameters have no local Modbus register, so the entities only exist on Cloud and Hybrid connections (reads and writes go through the cloud API in both — values refresh from the cloud roughly every 5 minutes, which also picks up portal-side edits). They are absent in pure-local mode, and they show unavailable on devices that do not carry the parameters.
- 255 sentinel: a factory-disabled End threshold reads
255("never stop"). The entity shows unknown with adisabled_sentinel: trueattribute in that state; 255 cannot be written from the 0-100 slider — set any 0-100 value to take control, or restore 255 from the EG4 portal.
For an on-demand transfer, toggling the switch is the simplest lever:
script:
drop_smart_port_power:
alias: "De-energize smart port before transfer"
sequence:
- service: switch.turn_off
target:
entity_id: switch.12000xp_1234567890_ac_coupleAlternatively, drive the SOC window (the source stays governed by battery level instead of being switched off outright):
script:
drop_smart_port_power_via_soc:
alias: "De-energize smart port via SOC window"
sequence:
- service: number.set_value
target:
entity_id: number.12000xp_1234567890_ac_couple_start_soc
data:
value: 1
- service: number.set_value
target:
entity_id: number.12000xp_1234567890_ac_couple_end_soc
data:
value: 11On an off-grid-configured inverter (e.g. 12000XP/6000XP running from battery/PV via AC First schedules), the Off-Grid binary sensor and the Operating State sensor report the inverter's mode — "running disconnected from the grid" — which is its normal steady state whether or not utility power is actually present. They do not flip when the grid drops, and the inverter logs no fault, warning, or EG4 event for a plain outage. The only reliable outage signal is grid voltage and frequency collapsing.
Build a debounced binary sensor from the Grid Voltage and Grid Frequency sensors:
# configuration.yaml
template:
- binary_sensor:
- name: "Grid Power Available"
device_class: power
# Grid is "up" only when BOTH voltage and frequency are in range.
# Tune the voltage bound to your grid: ~200 V for US split-phase (240 V
# nominal), ~200 V for 230 V single-phase, ~180 V per-leg for three-phase.
# Leave the sensor "unknown" when the source readings are missing,
# rather than defaulting to 0 (which would look like an outage).
state: >
{% set volt = states('sensor.18kpv_1234567890_grid_voltage') %}
{% set freq = states('sensor.18kpv_1234567890_grid_frequency') %}
{% if is_number(volt) and is_number(freq) %}
{{ volt | float > 200 and freq | float > 40 }}
{% endif %}
delay_on:
seconds: 10 # require 10 s of stable grid before declaring recovery
delay_off:
seconds: 5 # 5 s below threshold before declaring an outageThe asymmetric delay_on / delay_off mirrors how the inverter itself treats the grid:
quick to react to a loss, deliberately slow to trust a recovery (real inverters qualify
the returning grid against the configured grid standard, HOLD-203/205, before
reconnecting). Increase delay_on if brownouts or reconnect transients cause flapping.
Then alert on the edges:
automation:
- alias: "Notify on Grid Outage / Recovery"
trigger:
- platform: state
entity_id: binary_sensor.grid_power_available
to: "off"
id: outage
- platform: state
entity_id: binary_sensor.grid_power_available
to: "on"
id: recovered
action:
- service: notify.mobile_app
data:
title: "Grid Power"
message: >
{{ 'Grid outage detected' if trigger.id == 'outage'
else 'Grid power recovered' }}Why this isn't a built-in sensor: the "in range" thresholds are locale- and topology-specific (a value correct for US split-phase is wrong for 230 V single-phase or three-phase EU/BR units), and a faithful version needs the per-grid-standard reconnect timing above. A template keeps those choices in your hands.
Some events exist only in the EG4 portal's event log — transients that fall between register polls and are pushed to the cloud out-of-band by the device — so they never appear in the register-backed Fault/Warning Code sensors. In Cloud and Hybrid modes the integration surfaces them two ways:
-
Last Event sensor (diagnostic, per inverter and GridBOSS): state is the newest event's text (e.g.
Bus voltage high), withrecord_id(monotonic portal record id),event_code(E###/W###),event_type(FAULT/WARNING/…),start_time,end_timeandstatus(ACTIVE/RESOLVED) as attributes. Polled every 5 minutes; state is unknown when the device has no events.For exact new-event detection, trigger on the
record_id(orstart_time) attribute change rather than the state alone — two different events with identical text (e.g. a repeating fault) produce no state change:trigger: - platform: state entity_id: sensor.eg4_flexboss21_1234567890_last_event attribute: record_id condition: - "{{ trigger.to_state.state not in ('unknown', 'unavailable') }}"
Timezone note:
start_time/end_timeare naive timestamp strings in the portal's local timezone (no UTC offset, e.g.2026-07-01 16:50:28). Don't compare them tonow()in templates without accounting for that — convert with your plant's timezone first (e.g.strptime(...)+as_local/as_timestampwith an explicit zone). -
eg4_web_monitor.fetch_eventsservice: returns the recent event list on demand as response data (per device: normalized events + total count). Requires cloud credentials — calling it on a local-only entry raises an error. Fields:config_entry(required),serial(optional, default all inverters + GridBOSS),count(optional, default 30).
In pure Local mode the Last Event sensor is not created (the event log lives only in the cloud).
The integration registers these service actions (callable from Developer Tools → Actions or automations):
| Service | Description |
|---|---|
eg4_web_monitor.refresh_data |
Force an immediate refresh of all EG4 device data from the API. Optional entry_id targets a single config entry (default: all). |
eg4_web_monitor.reconcile_history |
Backfill missing energy statistics from the EG4 cloud for gaps in your energy-sensor history (requires cloud/hybrid mode). Accepts lookback_hours or an explicit start_date/end_date, and an optional entry_id. |
eg4_web_monitor.import_historical_data |
Import plant-level daily energy history (PV yield, consumption, grid import/export, battery charge/discharge) from the EG4 cloud into Home Assistant long-term statistics as external statistics, selectable in the Energy dashboard. |
eg4_web_monitor.fetch_events |
Fetch the recent portal event log (faults, warnings, notices) for one device or every inverter/GridBOSS in a config entry and return it as response data (requires cloud/hybrid mode). |
Example — force a data refresh:
action:
- service: eg4_web_monitor.refresh_dataSee each service's fields in Developer Tools → Actions (defined in services.yaml).
Common issues and fixes — including "Cannot connect", "Invalid username or password", "No stations found", unavailable entities, and missing sensors — are covered in docs/TROUBLESHOOTING.md.
To enable debug logging, add the following to configuration.yaml and restart
Home Assistant:
logger:
default: warning
logs:
custom_components.eg4_web_monitor: debugThen check Settings → System → Logs.
This integration meets the Home Assistant Platinum quality tier — the highest level — with fully async dependencies, websession injection, and strict typing, plus full translation support, UI reconfiguration, comprehensive automated testing, and professional error handling and logging.
This integration is built on the pylxpweb Python library. See docs/DEVELOPMENT.md to set up a development environment, and docs/ARCHITECTURE.md for design and structure.
- Join the JoyfulHouse Discord for support and discussion across all JoyfulHouse Home Assistant integrations and libraries.
- Issues: https://github.com/joyfulhouse/eg4_web_monitor/issues
- Discussions / questions: open an issue with the
questionlabel. - Community: Home Assistant Community and Home Assistant Discord.
If this project is useful to you, please consider supporting its development:
This project is licensed under the MIT License — see LICENSE for details.
This is an unofficial integration and is not affiliated with EG4 Electronics. Use at your own risk.
Built and maintained by JoyfulHouse with the pylxpweb library.
This integration was inspired by and built upon the work of @twistedroutes and the eg4_inverter_ha project. We extend our sincere gratitude for their pioneering efforts in EG4 device integration for Home Assistant.

