Skip to content

Commit fadd0a9

Browse files
committed
Rename integration from luxpower to luxcloud
- Renamed custom_components/luxpower/ → custom_components/luxcloud/ - Updated domain, DOMAIN constant, unique IDs, and device identifiers throughout - API URLs remain pointed at real luxpowertek.com endpoints - hacs.json name updated to LuxCloud - README updated (integration name LuxCloud, app/brand name LuxPower preserved) https://claude.ai/code/session_01RaoB8Zt3kjJRVZMoV6q56u
1 parent 46fb24c commit fadd0a9

14 files changed

Lines changed: 114 additions & 114 deletions

File tree

‎README.md‎

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# LuxPower — Home Assistant Integration
1+
# LuxCloud — Home Assistant Integration
22

33
[![HACS Badge](https://img.shields.io/badge/HACS-Custom-41BDF5.svg)](https://hacs.xyz)
44
[![Validate](https://github.com/BeardedTech0o/ha-solar-integration/actions/workflows/validate.yml/badge.svg)](https://github.com/BeardedTech0o/ha-solar-integration/actions/workflows/validate.yml)
55
[![GitHub Release](https://img.shields.io/github/v/release/BeardedTech0o/ha-solar-integration)](https://github.com/BeardedTech0o/ha-solar-integration/releases)
66

7-
Monitor and control your **LuxPower** solar inverter and battery from Home Assistant.
7+
Monitor and control your **LuxCloud** solar inverter and battery from Home Assistant.
88

99
---
1010

@@ -36,17 +36,17 @@ All entities appear under a single **device** named after your inverter serial n
3636
1. Open HACS in Home Assistant.
3737
2. Click the **⋮** menu → **Custom repositories**.
3838
3. Add `https://github.com/BeardedTech0o/ha-solar-integration` — category **Integration**.
39-
4. Search for **LuxPower** and click **Download**.
39+
4. Search for **LuxCloud** and click **Download**.
4040
5. Restart Home Assistant.
4141

4242
### Option B — Manual
4343

4444
1. Download the [latest release](https://github.com/BeardedTech0o/ha-solar-integration/releases/latest) zip.
45-
2. Extract the `luxpower/` folder into your `config/custom_components/` directory:
45+
2. Extract the `luxcloud/` folder into your `config/custom_components/` directory:
4646
```
4747
config/
4848
└── custom_components/
49-
└── luxpower/
49+
└── luxcloud/
5050
├── __init__.py
5151
├── manifest.json
5252
└── ...
@@ -58,7 +58,7 @@ All entities appear under a single **device** named after your inverter serial n
5858
## Setup
5959

6060
1. Go to **Settings → Devices & Services**.
61-
2. Click **+ Add Integration** and search for **LuxPower**.
61+
2. Click **+ Add Integration** and search for **LuxCloud**.
6262
3. Fill in the form:
6363

6464
| Field | What to enter |
@@ -80,33 +80,33 @@ All entities appear under a single **device** named after your inverter serial n
8080

8181
| Entity | Description |
8282
|--------|-------------|
83-
| `sensor.luxpower_SERIAL_solar_power` | Total solar generation in Watts. Positive = producing. |
84-
| `sensor.luxpower_SERIAL_battery_power` | Battery power in Watts. **Positive = charging**, negative = discharging. |
85-
| `sensor.luxpower_SERIAL_grid_power` | Grid power in Watts. **Positive = importing**, negative = exporting. |
86-
| `sensor.luxpower_SERIAL_load_power` | Home consumption in Watts. |
87-
| `sensor.luxpower_SERIAL_battery_state_of_charge` | Battery charge level (%). |
83+
| `sensor.luxcloud_SERIAL_solar_power` | Total solar generation in Watts. Positive = producing. |
84+
| `sensor.luxcloud_SERIAL_battery_power` | Battery power in Watts. **Positive = charging**, negative = discharging. |
85+
| `sensor.luxcloud_SERIAL_grid_power` | Grid power in Watts. **Positive = importing**, negative = exporting. |
86+
| `sensor.luxcloud_SERIAL_load_power` | Home consumption in Watts. |
87+
| `sensor.luxcloud_SERIAL_battery_state_of_charge` | Battery charge level (%). |
8888

8989
### Daily energy totals (reset at midnight)
9090

9191
| Entity | Description |
9292
|--------|-------------|
93-
| `sensor.luxpower_SERIAL_solar_energy_today` | kWh generated by solar panels today |
94-
| `sensor.luxpower_SERIAL_export_energy_today` | kWh sent to the grid today |
95-
| `sensor.luxpower_SERIAL_import_energy_today` | kWh taken from the grid today |
96-
| `sensor.luxpower_SERIAL_battery_charge_today` | kWh charged into the battery today |
97-
| `sensor.luxpower_SERIAL_battery_discharge_today` | kWh discharged from the battery today |
93+
| `sensor.luxcloud_SERIAL_solar_energy_today` | kWh generated by solar panels today |
94+
| `sensor.luxcloud_SERIAL_export_energy_today` | kWh sent to the grid today |
95+
| `sensor.luxcloud_SERIAL_import_energy_today` | kWh taken from the grid today |
96+
| `sensor.luxcloud_SERIAL_battery_charge_today` | kWh charged into the battery today |
97+
| `sensor.luxcloud_SERIAL_battery_discharge_today` | kWh discharged from the battery today |
9898

9999
All energy sensors are compatible with the **Energy Dashboard** (`state_class: total_increasing`).
100100

101101
### Controls
102102

103103
| Entity | Description |
104104
|--------|-------------|
105-
| `switch.luxpower_SERIAL_ac_charge` | Turn grid-to-battery charging on or off |
106-
| `number.luxpower_SERIAL_ac_charge_current_limit` | Maximum AC charge current (0–80 A) |
107-
| `number.luxpower_SERIAL_discharge_cutoff_soc` | Minimum SOC before the battery stops discharging (%) |
108-
| `number.luxpower_SERIAL_charge_cutoff_soc` | SOC at which charging stops (%) |
109-
| `select.luxpower_SERIAL_work_mode` | Operating mode: Self-use / Feed-in Priority / Backup / Manual |
105+
| `switch.luxcloud_SERIAL_ac_charge` | Turn grid-to-battery charging on or off |
106+
| `number.luxcloud_SERIAL_ac_charge_current_limit` | Maximum AC charge current (0–80 A) |
107+
| `number.luxcloud_SERIAL_discharge_cutoff_soc` | Minimum SOC before the battery stops discharging (%) |
108+
| `number.luxcloud_SERIAL_charge_cutoff_soc` | SOC at which charging stops (%) |
109+
| `select.luxcloud_SERIAL_work_mode` | Operating mode: Self-use / Feed-in Priority / Backup / Manual |
110110

111111
---
112112

@@ -127,7 +127,7 @@ Charge the battery from the grid overnight when tomorrow's solar forecast is low
127127

128128
```yaml
129129
automation:
130-
- alias: "LuxPower: charge overnight if solar forecast is low"
130+
- alias: "LuxCloud: charge overnight if solar forecast is low"
131131
trigger:
132132
- platform: time
133133
at: "22:00:00"
@@ -138,15 +138,15 @@ automation:
138138
action:
139139
- service: switch.turn_on
140140
target:
141-
entity_id: switch.luxpower_SERIAL_ac_charge
141+
entity_id: switch.luxcloud_SERIAL_ac_charge
142142
- service: number.set_value
143143
target:
144-
entity_id: number.luxpower_SERIAL_ac_charge_current_limit
144+
entity_id: number.luxcloud_SERIAL_ac_charge_current_limit
145145
data:
146146
value: 50
147147
- service: select.select_option
148148
target:
149-
entity_id: select.luxpower_SERIAL_work_mode
149+
entity_id: select.luxcloud_SERIAL_work_mode
150150
data:
151151
option: "Self Use"
152152
```
@@ -159,9 +159,9 @@ automation:
159159
160160
**"Invalid auth"** — Double-check your email and password. Note the password is case-sensitive. If you use social login (Google/Apple) in the app, you may need to set a password via *Forgot Password*.
161161
162-
**Entities show "Unavailable"** — The inverter may be offline (no internet, power cut). Check the app. Entities will recover automatically when it comes back.
162+
**Entities show "Unavailable"** — The inverter may be offline (no internet, power cut). Check the LuxPower app. Entities will recover automatically when it comes back.
163163
164-
**Data is stale** — The integration polls every 30 seconds. If your inverter has poor connectivity, increase the poll interval in `custom_components/luxpower/const.py` (`DEFAULT_SCAN_INTERVAL`).
164+
**Data is stale** — The integration polls every 30 seconds. If your inverter has poor connectivity, increase the poll interval in `custom_components/luxcloud/const.py` (`DEFAULT_SCAN_INTERVAL`).
165165

166166
---
167167

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""LuxPower Home Assistant integration."""
1+
"""LuxCloud Home Assistant integration."""
22
from __future__ import annotations
33

44
import logging
@@ -9,9 +9,9 @@
99
from homeassistant.core import HomeAssistant
1010
from homeassistant.helpers.aiohttp_client import async_get_clientsession
1111

12-
from .api import LuxPowerApi
12+
from .api import LuxCloudApi
1313
from .const import CONF_REGION, CONF_SERIAL, DOMAIN
14-
from .coordinator import LuxPowerCoordinator
14+
from .coordinator import LuxCloudCoordinator
1515

1616
_LOGGER = logging.getLogger(__name__)
1717

@@ -20,14 +20,14 @@
2020

2121
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
2222
session = async_get_clientsession(hass)
23-
api = LuxPowerApi(
23+
api = LuxCloudApi(
2424
session=session,
2525
username=entry.data[CONF_USERNAME],
2626
password=entry.data[CONF_PASSWORD],
2727
serial=entry.data[CONF_SERIAL],
2828
region=entry.data[CONF_REGION],
2929
)
30-
coordinator = LuxPowerCoordinator(hass, api)
30+
coordinator = LuxCloudCoordinator(hass, api)
3131
await coordinator.async_config_entry_first_refresh()
3232

3333
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""LuxPower cloud API client."""
1+
"""LuxCloud cloud API client."""
22
from __future__ import annotations
33

44
import asyncio
@@ -15,16 +15,16 @@
1515
_TOKEN_REFRESH_MARGIN = 300 # seconds before expiry to refresh
1616

1717

18-
class LuxPowerAuthError(Exception):
18+
class LuxCloudAuthError(Exception):
1919
"""Raised when authentication fails."""
2020

2121

22-
class LuxPowerApiError(Exception):
22+
class LuxCloudApiError(Exception):
2323
"""Raised on API communication errors."""
2424

2525

26-
class LuxPowerApi:
27-
"""Async client for the LuxPower cloud API."""
26+
class LuxCloudApi:
27+
"""Async client for the LuxCloud cloud API."""
2828

2929
def __init__(
3030
self,
@@ -66,7 +66,7 @@ async def _login(self) -> None:
6666
data = await self._post("/web/api/login", payload, auth=False)
6767
token = data.get("token")
6868
if not token:
69-
raise LuxPowerAuthError("No token returned from login")
69+
raise LuxCloudAuthError("No token returned from login")
7070
self._token = token
7171
loop = asyncio.get_event_loop()
7272
# expiration field is in seconds from epoch; fall back to 1 hour
@@ -102,15 +102,15 @@ async def _request(
102102
) as resp:
103103
if resp.status == 401:
104104
self._token = None
105-
raise LuxPowerAuthError("Authentication token rejected (401)")
105+
raise LuxCloudAuthError("Authentication token rejected (401)")
106106
resp.raise_for_status()
107107
body = await resp.json()
108108
except aiohttp.ClientError as exc:
109-
raise LuxPowerApiError(f"HTTP error talking to LuxPower: {exc}") from exc
109+
raise LuxCloudApiError(f"HTTP error talking to LuxCloud: {exc}") from exc
110110

111111
if not body.get("success", True):
112112
msg = body.get("msg") or body.get("message") or "Unknown API error"
113-
raise LuxPowerApiError(f"API error: {msg}")
113+
raise LuxCloudApiError(f"API error: {msg}")
114114
return body
115115

116116
async def _post(self, path: str, payload: dict, *, auth: bool = True) -> dict:
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
"""Config flow for LuxPower integration."""
1+
"""Config flow for LuxCloud integration."""
22
from __future__ import annotations
33

44
import voluptuous as vol
55
from homeassistant import config_entries
66
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
77
from homeassistant.helpers.aiohttp_client import async_get_clientsession
88

9-
from .api import LuxPowerApi, LuxPowerApiError, LuxPowerAuthError
9+
from .api import LuxCloudApi, LuxCloudApiError, LuxCloudAuthError
1010
from .const import (
1111
CONF_REGION,
1212
CONF_SERIAL,
@@ -34,8 +34,8 @@
3434
)
3535

3636

37-
class LuxPowerConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
38-
"""Handle the LuxPower configuration flow."""
37+
class LuxCloudConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
38+
"""Handle the LuxCloud configuration flow."""
3939

4040
VERSION = 1
4141

@@ -44,7 +44,7 @@ async def async_step_user(self, user_input=None):
4444

4545
if user_input is not None:
4646
session = async_get_clientsession(self.hass)
47-
api = LuxPowerApi(
47+
api = LuxCloudApi(
4848
session=session,
4949
username=user_input[CONF_USERNAME],
5050
password=user_input[CONF_PASSWORD],
@@ -53,17 +53,17 @@ async def async_step_user(self, user_input=None):
5353
)
5454
try:
5555
await api.async_validate_credentials()
56-
except LuxPowerAuthError:
56+
except LuxCloudAuthError:
5757
errors["base"] = "invalid_auth"
58-
except LuxPowerApiError:
58+
except LuxCloudApiError:
5959
errors["base"] = "cannot_connect"
6060
except Exception: # noqa: BLE001
6161
errors["base"] = "unknown"
6262
else:
6363
await self.async_set_unique_id(user_input[CONF_SERIAL])
6464
self._abort_if_unique_id_configured()
6565
return self.async_create_entry(
66-
title=f"LuxPower {user_input[CONF_SERIAL]}",
66+
title=f"LuxCloud {user_input[CONF_SERIAL]}",
6767
data=user_input,
6868
)
6969

@@ -87,7 +87,7 @@ async def async_step_reauth_confirm(self, user_input=None):
8787
existing = self._reauth_entry
8888
merged = {**existing.data, **user_input}
8989
session = async_get_clientsession(self.hass)
90-
api = LuxPowerApi(
90+
api = LuxCloudApi(
9191
session=session,
9292
username=merged[CONF_USERNAME],
9393
password=merged[CONF_PASSWORD],
@@ -96,9 +96,9 @@ async def async_step_reauth_confirm(self, user_input=None):
9696
)
9797
try:
9898
await api.async_validate_credentials()
99-
except LuxPowerAuthError:
99+
except LuxCloudAuthError:
100100
errors["base"] = "invalid_auth"
101-
except LuxPowerApiError:
101+
except LuxCloudApiError:
102102
errors["base"] = "cannot_connect"
103103
except Exception: # noqa: BLE001
104104
errors["base"] = "unknown"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
DOMAIN = "luxpower"
1+
DOMAIN = "luxcloud"
22
DEFAULT_SCAN_INTERVAL = 30
33

44
CONF_SERIAL = "serial_number"
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""DataUpdateCoordinator for LuxPower."""
1+
"""DataUpdateCoordinator for LuxCloud."""
22
from __future__ import annotations
33

44
import logging
@@ -9,16 +9,16 @@
99
from homeassistant.exceptions import ConfigEntryAuthFailed
1010
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
1111

12-
from .api import LuxPowerApi, LuxPowerApiError, LuxPowerAuthError
12+
from .api import LuxCloudApi, LuxCloudApiError, LuxCloudAuthError
1313
from .const import DEFAULT_SCAN_INTERVAL, DOMAIN
1414

1515
_LOGGER = logging.getLogger(__name__)
1616

1717

18-
class LuxPowerCoordinator(DataUpdateCoordinator[dict[str, Any]]):
19-
"""Polls LuxPower cloud API and distributes data to all entities."""
18+
class LuxCloudCoordinator(DataUpdateCoordinator[dict[str, Any]]):
19+
"""Polls LuxCloud cloud API and distributes data to all entities."""
2020

21-
def __init__(self, hass: HomeAssistant, api: LuxPowerApi) -> None:
21+
def __init__(self, hass: HomeAssistant, api: LuxCloudApi) -> None:
2222
super().__init__(
2323
hass,
2424
_LOGGER,
@@ -30,7 +30,7 @@ def __init__(self, hass: HomeAssistant, api: LuxPowerApi) -> None:
3030
async def _async_update_data(self) -> dict[str, Any]:
3131
try:
3232
return await self.api.async_get_runtime()
33-
except LuxPowerAuthError as exc:
33+
except LuxCloudAuthError as exc:
3434
raise ConfigEntryAuthFailed from exc
35-
except LuxPowerApiError as exc:
35+
except LuxCloudApiError as exc:
3636
raise UpdateFailed(str(exc)) from exc
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"domain": "luxpower",
3-
"name": "LuxPower Inverter",
2+
"domain": "luxcloud",
3+
"name": "LuxCloud Inverter",
44
"config_flow": true,
55
"documentation": "https://github.com/beardedtech0o/ha-solar-integration",
66
"requirements": ["aiohttp>=3.8.0"],

0 commit comments

Comments
 (0)