Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def device_info(self) -> DeviceInfo:
'identifiers': {(DOMAIN, "vhh")},
'manufacturer': "Powersensor",
'model': "Virtual",
'name': "Powersensor Household View",
'name': "Powersensor Household View 🏠",
}

async def async_added_to_hass(self):
Expand Down
22 changes: 10 additions & 12 deletions custom_components/powersensor/PowersensorSensorEntity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@

from .PowersensorEntity import PowersensorEntity
from .SensorMeasurements import SensorMeasurements
from .const import DOMAIN
from .const import DOMAIN, SENSOR_NAME_FORMAT

import logging
_LOGGER = logging.getLogger(__name__)


_config = {
# TODO: change names to translation keys
SensorMeasurements.Battery: {
"name": "Battery Level",
"device_class": SensorDeviceClass.BATTERY,
Expand Down Expand Up @@ -77,20 +78,17 @@ def _ensure_matching_prefix(self):

def _rename_based_on_role(self):
if self._device_name == self._default_device_name():
if self.role =='house-net':
self._device_name = "Powersensor Mains Sensor"
self._ensure_matching_prefix()
return True
elif self.role == 'water':
self._device_name = "Powersensor Water Sensor"
self._ensure_matching_prefix()
return True
elif self.role == 'solar':
self._device_name = "Powersensor Solar Sensor"
if self.role =='house-net' or self.role == "water" or self.role == "solar":
role2name = {
"house-net": "Powersensor Mains Sensor ⚡",
"solar": "Powersensor Solar Sensor ⚡",
"water": "Powersensor Water Sensor 💧",
}
self._device_name = role2name[self.role]
self._ensure_matching_prefix()
return True
return False

def _default_device_name(self):
return f'Powersensor Sensor (ID: {self._mac})'
return SENSOR_NAME_FORMAT % self._mac

87 changes: 45 additions & 42 deletions custom_components/powersensor/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.config_entries import ConfigFlowResult
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.service_info import zeroconf
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.helpers.selector import selector

from .const import DEFAULT_PORT, DOMAIN
from .const import DEFAULT_PORT, DOMAIN, SENSOR_NAME_FORMAT

def _extract_device_name(discovery_info) -> str:
"""Extract a user-friendly device name from zeroconf info."""
properties = discovery_info.properties or {}

if "id" in properties:
return f'🔌 Mac({properties["id"].strip()})'
return f"🔌 Mac({properties["id"].strip()})"

# Fall back to cleaning up the service name
name = discovery_info.name or ""

Expand All @@ -39,13 +42,6 @@ def _extract_device_name(discovery_info) -> str:

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
}
)


class PowersensorConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow."""
Expand All @@ -55,38 +51,45 @@ class PowersensorConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
def __init__(self):
"""Initialize the config flow."""

# async def async_step_user(self, user_input=None) -> ConfigFlowResult:
# """Handle manual user setup."""
# errors = {}
#
# if user_input is not None:
# # Validate the host/connection here if needed
# try:
# # Set unique ID based on host to prevent duplicates
# await self.async_set_unique_id(user_input[CONF_HOST])
# self._abort_if_unique_id_configured()
#
# return self.async_create_entry(
# title=user_input[CONF_NAME],
# data=user_input
# )
# except Exception as ex:
# _LOGGER.error("Error validating configuration: %s", ex)
# errors["base"] = "cannot_connect"
#
# data_schema = vol.Schema(
# {
# vol.Required(CONF_NAME): cv.string,
# vol.Required(CONF_HOST): cv.string,
# vol.Optional(CONF_PORT, default=80): cv.port,
# }
# )
#
# return self.async_show_form(
# step_id="user",
# data_schema=data_schema,
# errors=errors
# )
async def async_step_reconfigure(self, user_input: dict | None = None)->FlowResult:
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
dispatcher = entry.runtime_data["dispatcher"]

mac2name = { mac: SENSOR_NAME_FORMAT % mac for mac in dispatcher.sensors }

unknown = "<unknown>"
if user_input is not None:
name2mac = { name: mac for mac, name in mac2name.items() }
for name, role in user_input.items():
mac = name2mac.get(name)
if role == unknown:
role = None
_LOGGER.debug(f"Applying {role} to {mac}")
async_dispatcher_send(self.hass, f"{DOMAIN}_update_role", mac, role)
return self.async_abort(reason="Roles successfully applied!")

sensor_roles = {}
for sensor_mac in dispatcher.sensors:
role = entry.data.get('roles', {}).get(sensor_mac, unknown)
sel = selector({
"select": {
"options": [
# Note: these strings are NOT subject to translation
"house-net", "solar", "water", "appliance", unknown
],
"mode": "dropdown",
}
})
sensor_roles[vol.Optional(mac2name[sensor_mac], description={"suggested_value": role})] = sel

return self.async_show_form(
step_id="reconfigure",
data_schema=vol.Schema(sensor_roles),
description_placeholders={
"device_count": str(len(sensor_roles)),
"docs_url" : "https://dius.github.io/homeassistant-powersensor/data.html#virtual-household"
}
)

async def async_step_zeroconf(
self, discovery_info: zeroconf.ZeroconfServiceInfo
Expand Down
5 changes: 2 additions & 3 deletions custom_components/powersensor/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@
DEFAULT_PORT = 49476
DEFAULT_SCAN_INTERVAL = 30
POWER_SENSOR_UPDATE_SIGNAL = f"{DOMAIN}_sensor"
# Configuration keys
CONF_HOST = "host"
CONF_PORT = "port"

SENSOR_NAME_FORMAT = "Powersensor Sensor (ID: %s) ⚡"
12 changes: 4 additions & 8 deletions custom_components/powersensor/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,16 @@
"config": {
"title" : "Powersensor",
"step": {
"user": {
"description": "Enter the connection details for your device",
"data": {
"host": "Host",
"port": "Port"
}
},
"discovery_confirm": {
"description": "Do you want to add Powersensor to Home Assistant?",
"title": "Powersensor plugs discovered"
},
"reconfigure" : {
"title" : "Update sensor roles",
"description": "Note: Roles provided by sensors will override user settings"
}
},
"error": {
"cannot_connect": "Failed to connect",
"unknown": "Unexpected error"
},
"abort": {
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

# Project information
project = "homeassistant-powersensor"
copyright = "2025, DiUS"
copyright = "2025, Powersensor"
author = "Powersensor Team!"

html_favicon = "_static/powersensor-logo.png"
Expand Down
Loading