├── .github └── workflows │ └── hacs.yml ├── .gitignore ├── README.md ├── custom_components └── start_time │ ├── __init__.py │ ├── config_flow.py │ ├── manifest.json │ └── sensor.py ├── hacs.json └── sensor.png /.github/workflows/hacs.yml: -------------------------------------------------------------------------------- 1 | name: HACS validation 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | hacs: 9 | runs-on: "ubuntu-latest" 10 | steps: 11 | - uses: "actions/checkout@v2" 12 | - uses: "hacs/action@main" 13 | with: { category: "integration" } 14 | hassfest: 15 | runs-on: "ubuntu-latest" 16 | steps: 17 | - uses: "actions/checkout@v3" 18 | - uses: "home-assistant/actions/hassfest@master" 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | __pycache__/ 3 | 4 | .homeassistant/ 5 | 6 | .idea/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StartTime for Home Assistant 2 | 3 | [![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs) 4 | 5 | Create Start Time sensor for [Home Assistant](https://www.home-assistant.io/). 6 | 7 | ![sensor](sensor.png) 8 | 9 | ## Installation 10 | 11 | **Method 1.** [HACS](https://hacs.xyz/) custom repo: 12 | 13 | > HACS > Integrations > 3 dots (upper top corner) > Custom repositories > URL: `AlexxIT/StartTime`, Category: Integration > Add > wait > StartTime > Install 14 | 15 | **Method 2.** Manually copy `start_time` folder from [latest release](https://github.com/AlexxIT/StartTime/releases/latest) to `/config/custom_components` folder. 16 | 17 | ## Configuration 18 | 19 | **Method 1.** GUI: 20 | 21 | > Configuration > Integrations > Add Integration > **StartTime** 22 | 23 | If the integration is not in the list, you need to clear the browser cache. 24 | 25 | **Method 2.** YAML: 26 | 27 | ```yaml 28 | start_time: 29 | ``` 30 | 31 | ## About 32 | 33 | Home Assistant displays initialization time in INFO logs. The component shows the same time as a sensor. 34 | 35 | Useful for debugging performance of slow computers like Raspberry Pi. 36 | 37 | This component does not depend on the settings of the `logger` component! 38 | 39 | ``` 40 | 2020-02-24 17:13:11 INFO (MainThread) [homeassistant.bootstrap] Home Assistant initialized in 25.5s 41 | ``` 42 | -------------------------------------------------------------------------------- /custom_components/start_time/__init__.py: -------------------------------------------------------------------------------- 1 | from homeassistant.config_entries import ConfigEntry, SOURCE_IMPORT 2 | from homeassistant.core import HomeAssistant 3 | 4 | from .sensor import DOMAIN, StartTime 5 | 6 | 7 | async def async_setup(hass: HomeAssistant, hass_config: dict): 8 | hass.data[DOMAIN] = StartTime() 9 | 10 | if DOMAIN in hass_config and not hass.config_entries.async_entries(DOMAIN): 11 | hass.async_create_task(hass.config_entries.flow.async_init( 12 | DOMAIN, context={"source": SOURCE_IMPORT} 13 | )) 14 | return True 15 | 16 | 17 | async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry): 18 | hass.async_create_task(hass.config_entries.async_forward_entry_setup( 19 | config_entry, 'sensor' 20 | )) 21 | return True 22 | -------------------------------------------------------------------------------- /custom_components/start_time/config_flow.py: -------------------------------------------------------------------------------- 1 | from homeassistant.config_entries import ConfigFlow 2 | 3 | from . import DOMAIN 4 | 5 | 6 | class ConfigFlowHandler(ConfigFlow, domain=DOMAIN): 7 | async def async_step_import(self, user_input=None): 8 | return await self.async_step_user() 9 | 10 | async def async_step_user(self, user_input=None): 11 | if self._async_current_entries(): 12 | return self.async_abort(reason='single_instance_allowed') 13 | return self.async_create_entry(title="Start Time", data={}) 14 | -------------------------------------------------------------------------------- /custom_components/start_time/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "start_time", 3 | "name": "Start Time", 4 | "codeowners": [ 5 | "@AlexxIT" 6 | ], 7 | "config_flow": true, 8 | "dependencies": [], 9 | "documentation": "https://github.com/AlexxIT/StartTime", 10 | "iot_class": "calculated", 11 | "issue_tracker": "https://github.com/AlexxIT/StartTime/issues", 12 | "requirements": [], 13 | "version": "1.1.8" 14 | } 15 | -------------------------------------------------------------------------------- /custom_components/start_time/sensor.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from datetime import timedelta 3 | 4 | from homeassistant.core import HomeAssistant 5 | from homeassistant.helpers.entity import Entity 6 | 7 | _LOGGER = logging.getLogger(__name__) 8 | 9 | DOMAIN = "start_time" 10 | 11 | 12 | async def async_setup_entry(hass: HomeAssistant, entry, async_add_entities): 13 | sensor = hass.data[DOMAIN] 14 | async_add_entities([sensor]) 15 | 16 | 17 | class StartTime(Entity): 18 | def __init__(self): 19 | self._attr_icon = "mdi:home-assistant" 20 | self._attr_name = "Start Time" 21 | self._attr_should_poll = False 22 | self._attr_unit_of_measurement = "seconds" 23 | self._attr_unique_id = DOMAIN 24 | 25 | self.add_logger("homeassistant.bootstrap") 26 | 27 | def add_logger(self, name: str): 28 | logger = logging.getLogger(name) 29 | real_info = logger.info 30 | 31 | def monkey_info(msg: str, *args): 32 | # https://github.com/home-assistant/core/issues/112464 33 | try: 34 | if msg.startswith("Home Assistant initialized"): 35 | self.internal_update(args[0]) 36 | except Exception as e: 37 | _LOGGER.warning("update error", exc_info=e) 38 | 39 | real_info(msg, *args) 40 | 41 | logger.info = monkey_info 42 | 43 | def internal_update(self, state: float): 44 | setup_time: dict = self.hass.data.get("setup_time") 45 | if setup_time: 46 | extra = {} # protect original dict from changing 47 | 48 | for k, v in setup_time.items(): 49 | if isinstance(v, dict): # Hass 2024.4 50 | value = sum(j for i in v.values() for j in i.values()) 51 | extra[k] = round(value, 2) 52 | elif isinstance(v, float): # Hass 2024.3 53 | extra[k] = round(v, 2) 54 | elif isinstance(v, timedelta): # before Hass 2024.3 55 | extra[k] = round(v.total_seconds(), 2) 56 | else: 57 | continue 58 | 59 | self._attr_extra_state_attributes = dict( 60 | sorted(extra.items(), key=lambda kv: kv[1], reverse=True) 61 | ) 62 | 63 | self._attr_state = round(state, 2) 64 | 65 | self.schedule_update_ha_state() 66 | -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Start Time", 3 | "render_readme": true 4 | } -------------------------------------------------------------------------------- /sensor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlexxIT/StartTime/bc41fda52a9a2f0e4eaf2fe0a6e18b7f13d52b68/sensor.png --------------------------------------------------------------------------------