@hakit/core
Version:
A collection of React hooks and helpers for Home Assistant to easily communicate with the Home Assistant WebSocket API.
1 lines • 16.2 kB
Source Map (JSON)
{"version":3,"file":"index-CqE3ydBk.cjs","sources":["../src/hooks/useEntity/index.ts","../src/hooks/useIcon/index.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { HassEntityWithService, HassEntityCustom, ExtractDomain, EntityName } from \"@typings\";\nimport type { HassEntity } from \"home-assistant-js-websocket\";\nimport { getCssColorValue } from \"@utils/colors\";\nimport { timeAgo } from \"@utils/time/time-ago\";\nimport { computeDomain, useStore, useSubscribeEntity, useHistory, useService, getIconByEntity, type HistoryOptions } from \"@core\";\n\nexport interface UseEntityOptions {\n returnNullIfNotFound?: boolean;\n historyOptions?: HistoryOptions;\n}\n\nconst DEFAULT_OPTIONS: Required<UseEntityOptions> = {\n returnNullIfNotFound: false,\n historyOptions: {\n hoursToShow: 24,\n significantChangesOnly: true,\n minimalResponse: true,\n disable: true,\n },\n};\n\nexport type UseEntityReturnType<E, O extends UseEntityOptions> = O[\"returnNullIfNotFound\"] extends true\n ? HassEntityWithService<ExtractDomain<E>> | null\n : HassEntityWithService<ExtractDomain<E>>;\n\nfunction formatEntity(entity: HassEntity, language: string | undefined): HassEntityCustom {\n const now = new Date();\n const then = new Date(entity.attributes.last_triggered ?? entity.last_updated);\n const relativeTime = timeAgo(then, language);\n const timeDiff = Math.abs(now.getTime() - then.getTime());\n const active = relativeTime === \"just now\";\n const { hexColor, rgbColor, brightness, brightnessValue, rgbaColor, color } = getCssColorValue(entity);\n const currentIcon = getIconByEntity(computeDomain(entity.entity_id as EntityName), entity);\n return {\n ...entity,\n attributes: {\n ...entity.attributes,\n icon: entity.attributes?.icon || currentIcon,\n },\n custom: {\n color,\n relativeTime,\n timeDiff,\n active,\n hexColor,\n rgbColor,\n brightness,\n brightnessValue,\n rgbaColor,\n },\n };\n}\n\nexport function useEntity<E extends EntityName, O extends UseEntityOptions = UseEntityOptions>(\n entity: E,\n options: O = DEFAULT_OPTIONS as O,\n): UseEntityReturnType<E, O> {\n const { returnNullIfNotFound, historyOptions } = {\n ...DEFAULT_OPTIONS,\n ...options,\n historyOptions: {\n ...DEFAULT_OPTIONS.historyOptions,\n ...options.historyOptions,\n },\n };\n const getEntity = useSubscribeEntity(entity);\n const rawEntity = getEntity(returnNullIfNotFound);\n const domain = computeDomain(entity) as ExtractDomain<E>;\n const service = useService(domain, entity);\n const history = useHistory(entity, historyOptions);\n const language = useStore((state) => state.config?.language);\n const formatted = useMemo(() => (rawEntity ? formatEntity(rawEntity, language) : null), [rawEntity, language]);\n const entityWithHelpers = useMemo(() => {\n if (formatted == null) {\n // purposely casting here so types are correct on usage side\n // if returnNullIfNotFound is true, we return null, if not we throw an error\n return null as unknown as UseEntityReturnType<E, O>;\n }\n return { ...formatted, service, history } as UseEntityReturnType<E, O>;\n }, [formatted, service, history]);\n\n return entityWithHelpers;\n}\n","import { useMemo } from \"react\";\nimport { Icon as IconElement } from \"@iconify/react\";\nimport type { IconProps } from \"@iconify/react\";\nimport { useEntity, computeDomain, AllDomains, CamelToSnake, EntityName } from \"@core\";\nimport { snakeCase } from \"lodash\";\nimport { HassEntity } from \"home-assistant-js-websocket\";\n\nimport { binarySensorIcon } from \"./domains/binary_sensor\";\nimport { sensorIcon } from \"./domains/sensor\";\nimport { numberIcon } from \"./domains/number\";\nimport { coverIcon } from \"./domains/cover\";\nimport { alarmPanelIcon } from \"./domains/alarm\";\nimport { weatherIcon } from \"./domains/weather\";\nimport { FIXED_DOMAIN_ICONS } from \"./domains/constants\";\n\nexport { batteryIconByLevel } from \"./domains/battery\";\n\nexport function useIconByDomain<D extends AllDomains | CamelToSnake<AllDomains> | \"unknown\">(\n domain: D,\n iconProps?: Omit<IconProps, \"icon\">,\n) {\n const iconName = useMemo(() => {\n const convertedDomainName = snakeCase(domain) as keyof typeof FIXED_DOMAIN_ICONS;\n if (FIXED_DOMAIN_ICONS[convertedDomainName]) {\n return FIXED_DOMAIN_ICONS[convertedDomainName];\n }\n // If the domain does not match any case, we just return an info icon\n return \"mdi:information-outline\";\n }, [domain]);\n if (iconName === null) {\n return null;\n }\n return (\n <IconElement\n style={{\n fontSize: iconProps?.fontSize ?? \"24px\",\n }}\n icon={iconName}\n {...iconProps}\n />\n );\n}\n\nexport function useIcon(icon: string | null, iconProps?: Omit<IconProps, \"icon\">) {\n const Icon = useMemo(() => {\n if (icon === null) return null;\n return (\n <IconElement\n style={{\n fontSize: iconProps?.fontSize ?? \"24px\",\n }}\n icon={icon || \"octicon:info-24\"}\n {...iconProps}\n />\n );\n }, [icon, iconProps]);\n return Icon;\n}\n\nexport function getIconByEntity(domain: string, entity: HassEntity): string | undefined {\n const compareState = entity.state;\n\n switch (domain) {\n case \"alarm_control_panel\":\n return alarmPanelIcon(compareState);\n\n case \"automation\":\n return compareState === \"unavailable\" ? \"mdi:robot-confused\" : compareState === \"off\" ? \"mdi:robot-off\" : \"mdi:robot\";\n\n case \"binary_sensor\":\n return binarySensorIcon(entity);\n\n case \"button\":\n switch (entity.attributes.device_class) {\n case \"identify\":\n return \"mdi:crosshairs-question\";\n case \"restart\":\n return \"mdi:restart\";\n case \"update\":\n return \"mdi:package-up\";\n default:\n return \"mdi:button-pointer\";\n }\n\n case \"camera\":\n return compareState === \"off\" ? \"mdi:video-off\" : \"mdi:video\";\n\n case \"cover\":\n return coverIcon(entity);\n\n case \"device_tracker\":\n if (entity.attributes.source_type === \"router\") {\n return compareState === \"home\" ? \"mdi:lan-connect\" : \"mdi:lan-disconnect\";\n }\n if ([\"bluetooth\", \"bluetooth_le\"].includes(entity.attributes.source_type)) {\n return compareState === \"home\" ? \"mdi:bluetooth-connect\" : \"mdi:bluetooth\";\n }\n return compareState === \"not_home\" ? \"mdi:account-arrow-right\" : \"mdi:account\";\n\n case \"event\":\n switch (entity.attributes.device_class) {\n case \"doorbell\":\n return \"mdi:doorbell\";\n case \"button\":\n return \"mdi:gesture-tap-button\";\n case \"motion\":\n return \"mdi:motion-sensor\";\n default:\n return \"mdi:eye-check\";\n }\n\n case \"fan\":\n return compareState === \"off\" ? \"mdi:fan-off\" : \"mdi:fan\";\n\n case \"humidifier\":\n return compareState === \"off\" ? \"mdi:air-humidifier-off\" : \"mdi:air-humidifier\";\n\n case \"input_boolean\":\n return compareState === \"on\" ? \"mdi:check-circle-outline\" : \"mdi:close-circle-outline\";\n\n case \"input_datetime\":\n if (!entity.attributes.has_date) {\n return \"mdi:clock\";\n }\n if (!entity.attributes.has_time) {\n return \"mdi:calendar\";\n }\n break;\n\n case \"lock\":\n switch (compareState) {\n case \"unlocked\":\n return \"mdi:lock-open\";\n case \"jammed\":\n return \"mdi:lock-alert\";\n case \"locking\":\n case \"unlocking\":\n return \"mdi:lock-clock\";\n default:\n return \"mdi:lock\";\n }\n\n case \"media_player\":\n switch (entity.attributes.device_class) {\n case \"speaker\":\n switch (compareState) {\n case \"playing\":\n return \"mdi:speaker-play\";\n case \"paused\":\n return \"mdi:speaker-pause\";\n case \"off\":\n return \"mdi:speaker-off\";\n default:\n return \"mdi:speaker\";\n }\n case \"tv\":\n switch (compareState) {\n case \"playing\":\n return \"mdi:television-play\";\n case \"paused\":\n return \"mdi:television-pause\";\n case \"off\":\n return \"mdi:television-off\";\n default:\n return \"mdi:television\";\n }\n case \"receiver\":\n switch (compareState) {\n case \"off\":\n return \"mdi:audio-video-off\";\n default:\n return \"mdi:audio-video\";\n }\n default:\n switch (compareState) {\n case \"playing\":\n case \"paused\":\n return \"mdi:cast-connected\";\n case \"off\":\n return \"mdi:cast-off\";\n default:\n return \"mdi:cast\";\n }\n }\n\n case \"number\": {\n const icon = numberIcon(entity);\n if (icon) {\n return icon;\n }\n\n break;\n }\n\n case \"person\":\n return compareState === \"not_home\" ? \"mdi:account-arrow-right\" : \"mdi:account\";\n\n case \"switch\":\n switch (entity.attributes.device_class) {\n case \"outlet\":\n return compareState === \"on\" ? \"mdi:power-plug\" : \"mdi:power-plug-off\";\n case \"switch\":\n return compareState === \"on\" ? \"mdi:toggle-switch-variant\" : \"mdi:toggle-switch-variant-off\";\n default:\n return \"mdi:toggle-switch-variant\";\n }\n\n case \"sensor\": {\n const icon = sensorIcon(entity);\n if (icon) {\n return icon;\n }\n break;\n }\n\n case \"sun\":\n return entity.state === \"above_horizon\" ? \"mdi:white-balance-sunny\" : \"mdi:weather-night\";\n\n case \"switch_as_x\":\n return \"mdi:swap-horizontal\";\n\n case \"threshold\":\n return \"mdi:chart-sankey\";\n\n case \"update\":\n return \"mdi:package\";\n case \"water_heater\":\n return compareState === \"off\" ? \"mdi:water-boiler-off\" : \"mdi:water-boiler\";\n\n case \"weather\":\n return weatherIcon(entity.state);\n }\n\n if (domain in FIXED_DOMAIN_ICONS) {\n return FIXED_DOMAIN_ICONS[domain as keyof typeof FIXED_DOMAIN_ICONS];\n }\n\n return undefined;\n}\n\nexport function useIconByEntity<E extends EntityName>(_entity: E, iconProps?: Omit<IconProps, \"icon\">) {\n const entity = useEntity(_entity || \"unknown\", {\n returnNullIfNotFound: true,\n });\n const Icon = useMemo(() => {\n if (entity === null) return null;\n const icon = entity.attributes.icon ?? getIconByEntity(computeDomain(_entity), entity);\n if (!icon) {\n return null;\n }\n return (\n <IconElement\n style={{\n fontSize: iconProps?.fontSize ?? \"24px\",\n }}\n icon={icon}\n {...iconProps}\n />\n );\n }, [entity, _entity, iconProps]);\n return Icon;\n}\n"],"names":["DEFAULT_OPTIONS","formatEntity","entity","language","now","then","relativeTime","timeAgo","timeDiff","active","hexColor","rgbColor","brightness","brightnessValue","rgbaColor","color","getCssColorValue","currentIcon","getIconByEntity","computeDomain","useEntity","options","returnNullIfNotFound","historyOptions","rawEntity","useSubscribeEntity","domain","service","useService","history","useHistory","useStore","state","formatted","useMemo","useIconByDomain","iconProps","iconName","convertedDomainName","snakeCase","FIXED_DOMAIN_ICONS","jsx","IconElement","useIcon","icon","compareState","alarmPanelIcon","binarySensorIcon","coverIcon","numberIcon","sensorIcon","weatherIcon","useIconByEntity","_entity"],"mappings":"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"}