Help with adding descriptions to custom component gui

Hi all,

I’m having difficulty adding a description of the custom component along with selection box descriptions. Can anybody please assist?
My code below presents the following:

image

Ideally, I’d like the “wizard” / GUI to look something like this:

.

manifest.json

{
  "domain": "energy_bill_estimator",
  "name": "Energy Bill Estimator",
  "version": "1.0.0",
  "documentation": "https://github.com/pppaulie/energy_bill_estimator/",
  "requirements": [],
  "codeowners": ["@pppaulie"],
  "config_flow": true,
  "iot_class": "local_polling",
  "issue_tracker": "https://github.com/pppaulie/energy_bill_estimator/issues"
}

init.py

"""Initialize the Energy Bill Estimator integration."""
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from .const import DOMAIN

async def async_setup(hass: HomeAssistant, config: dict):
    """Set up the Energy Bill Estimator integration."""
    hass.data.setdefault(DOMAIN, {})
    return True

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
    """Set up Energy Bill Estimator from a config entry."""
    hass.async_create_task(
        hass.config_entries.async_forward_entry_setup(entry, "sensor")
    )
    return True

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
    """Unload Energy Bill Estimator config entry."""
    await hass.config_entries.async_forward_entry_unload(entry, "sensor")
    return True

const.py

"""Constants for the Energy Bill Estimator integration."""

DOMAIN = "energy_bill_estimator"

CONF_ENERGY_COST_SENSOR = "energy_cost_sensor"

CONF_SUPPLY_COST_ENTITY = "supply_cost_entity"

config_flow.py

"""Config flow for Energy Bill Estimator integration."""
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.helpers import selector

from .const import DOMAIN, CONF_ENERGY_COST_SENSOR, CONF_SUPPLY_COST_ENTITY

class EnergyBillEstimatorConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """Handle a config flow for Energy Bill Estimator."""

    VERSION = 1

    async def async_step_user(self, user_input=None):
        """Handle the initial step."""
        if user_input is not None:
            return self.async_create_entry(title="Energy Bill Estimator", data=user_input)

        data_schema = vol.Schema({
            vol.Required(CONF_ENERGY_COST_SENSOR): selector.EntitySelector(
                selector.EntitySelectorConfig(domain="sensor")
            ),
            vol.Required(CONF_SUPPLY_COST_ENTITY): selector.EntitySelector(
                selector.EntitySelectorConfig(domain=["input_number", "sensor"])
            ),
        })

        return self.async_show_form(
            step_id="user",
            data_schema=data_schema,
        )

strings.json

{
  "title": "Energy Bill Estimator",
  "config": {
    "step": {
      "user": {
        "title": "Configure Energy Bill Estimator",
        "description": "Select the entities for energy cost and supply cost.",
        "data": {
          "energy_cost_sensor": "House Monthly Energy Cost Sensor",
          "supply_cost_entity": "Daily Supply Cost Entity"
        }
      }
    }
  }
}

sensor.py

"""Sensor platform for Energy Bill Estimator integration."""
from datetime import timedelta

from homeassistant.components.sensor import SensorEntity
from homeassistant.const import CURRENCY_DOLLAR
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.util.dt import now as ha_now

from .const import DOMAIN, CONF_ENERGY_COST_SENSOR, CONF_SUPPLY_COST_ENTITY

async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities):
    """Set up the Energy Bill Estimator sensor platform."""
    async_add_entities([EnergyBillEstimatorSensor(hass, config_entry)], True)

class EnergyBillEstimatorSensor(SensorEntity):
    """Representation of the Energy Bill Estimator sensor."""

    def __init__(self, hass, config_entry):
        """Initialize the sensor."""
        self.hass = hass
        self.config_entry = config_entry
        self._attr_name = "Energy Bill Estimate"
        self._attr_unique_id = f"{DOMAIN}_sensor"
        self._state = None
        self._attr_unit_of_measurement = CURRENCY_DOLLAR
        self._attr_extra_state_attributes = {}

    async def async_update(self):
        """Fetch new state data for the sensor."""
        energy_cost_entity = self.config_entry.data[CONF_ENERGY_COST_SENSOR]
        supply_cost_entity = self.config_entry.data[CONF_SUPPLY_COST_ENTITY]

        energy_cost_state = self.hass.states.get(energy_cost_entity)
        supply_cost_state = self.hass.states.get(supply_cost_entity)

        # Error handling for unavailable entities
        if energy_cost_state is None or supply_cost_state is None:
            self._state = None
            return

        if energy_cost_state.state in [None, "unknown", "unavailable"] or \
           supply_cost_state.state in [None, "unknown", "unavailable"]:
            self._state = None
            return

        try:
            energy_cost = float(energy_cost_state.state)
            supply_cost = float(supply_cost_state.state)
        except (ValueError, TypeError):
            self._state = None
            return

        now = ha_now()  # Use Home Assistant's time zone

        # Corrected billing cycle calculations
        if now.day >= 27:
            # Billing cycle starts this month on the 27th
            billing_cycle_start = now.replace(day=27)
            # Next month's 27th
            next_month = (now.month % 12) + 1
            next_year = now.year + 1 if now.month == 12 else now.year
            try:
                billing_cycle_end = billing_cycle_start.replace(year=next_year, month=next_month)
            except ValueError:
                # Handle months where the next month doesn't have 27 days
                billing_cycle_end = (billing_cycle_start + timedelta(days=31)).replace(day=27)
        else:
            # Billing cycle started last month on the 27th
            prev_month = (now.month - 2) % 12 + 1
            prev_year = now.year - 1 if now.month == 1 else now.year
            try:
                billing_cycle_start = now.replace(year=prev_year, month=prev_month, day=27)
            except ValueError:
                # Handle months where the previous month doesn't have 27 days
                billing_cycle_start = (now - timedelta(days=now.day)).replace(day=27)
            billing_cycle_end = now.replace(day=27)

        # Adjust dates to include both start and end dates
        days_in_billing_cycle = (billing_cycle_end - billing_cycle_start).days + 1
        days_in_billing_cycle = days_in_billing_cycle if days_in_billing_cycle > 0 else 1  # Avoid zero

        days_past = (now - billing_cycle_start).days + 1
        days_past = days_past if days_past > 0 else 1  # Avoid zero

        days_remaining = days_in_billing_cycle - days_past
        days_remaining = days_remaining if days_remaining >= 0 else 0

        average_daily_cost = energy_cost / days_past if days_past > 0 else 0

        total_supply_cost = supply_cost * days_in_billing_cycle
        total_estimated_cost = (average_daily_cost * days_in_billing_cycle) + total_supply_cost

        # Update the state and attributes
        self._state = round(total_estimated_cost, 2)
        self._attr_extra_state_attributes = {
            "Days in Billing Cycle": days_in_billing_cycle,
            "Days Remaining": days_remaining,
            "Days Past": days_past,
            "Average Daily Cost": f"${average_daily_cost:.2f}",
            "Total Monthly Supply Cost": f"${total_supply_cost:.2f}",
        }

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state`Preformatted text`

strings.json is not used for custom integrations you need to put the contents of that file to translations/en.json (inside your component folder)