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
29 changes: 23 additions & 6 deletions homeassistant/components/purpleair/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""The PurpleAir integration."""
from __future__ import annotations

from collections.abc import Mapping
from typing import Any

from aiopurpleair.models.sensors import SensorModel

from homeassistant.config_entries import ConfigEntry
Expand All @@ -9,7 +12,7 @@
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import DOMAIN
from .const import CONF_SHOW_ON_MAP, DOMAIN
from .coordinator import PurpleAirDataUpdateCoordinator

PLATFORMS = [Platform.SENSOR]
Expand Down Expand Up @@ -60,16 +63,30 @@ def __init__(
self._attr_device_info = DeviceInfo(
configuration_url=self.coordinator.async_get_map_url(sensor_index),
hw_version=self.sensor_data.hardware,
identifiers={(DOMAIN, str(self._sensor_index))},
identifiers={(DOMAIN, str(sensor_index))},
manufacturer="PurpleAir, Inc.",
model=self.sensor_data.model,
name=self.sensor_data.name,
sw_version=self.sensor_data.firmware_version,
)
self._attr_extra_state_attributes = {
ATTR_LATITUDE: self.sensor_data.latitude,
ATTR_LONGITUDE: self.sensor_data.longitude,
}
self._entry = entry

@property
def extra_state_attributes(self) -> Mapping[str, Any]:
Comment thread
bachya marked this conversation as resolved.
"""Return entity specific state attributes."""
attrs = {}

# Displaying the geography on the map relies upon putting the latitude/longitude
# in the entity attributes with "latitude" and "longitude" as the keys.
# Conversely, we can hide the location on the map by using other keys, like
# "lati" and "long":
if self._entry.options.get(CONF_SHOW_ON_MAP):
attrs[ATTR_LATITUDE] = self.sensor_data.latitude
attrs[ATTR_LONGITUDE] = self.sensor_data.longitude
else:
attrs["lati"] = self.sensor_data.latitude
attrs["long"] = self.sensor_data.longitude
Comment thread
bachya marked this conversation as resolved.
Comment thread
bachya marked this conversation as resolved.
return attrs

@property
def sensor_data(self) -> SensorModel:
Expand Down
36 changes: 32 additions & 4 deletions homeassistant/components/purpleair/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
SelectSelectorMode,
)

from .const import CONF_SENSOR_INDICES, DOMAIN, LOGGER
from .const import CONF_SENSOR_INDICES, CONF_SHOW_ON_MAP, DOMAIN, LOGGER

CONF_DISTANCE = "distance"
CONF_NEARBY_SENSOR_OPTIONS = "nearby_sensor_options"
Expand Down Expand Up @@ -318,6 +318,22 @@ def __init__(self, config_entry: ConfigEntry) -> None:
self._flow_data: dict[str, Any] = {}
self.config_entry = config_entry

@property
def settings_schema(self) -> vol.Schema:
"""Return the settings schema."""
return vol.Schema(
{
vol.Optional(
CONF_SHOW_ON_MAP,
description={
"suggested_value": self.config_entry.options.get(
CONF_SHOW_ON_MAP
)
},
): bool
}
)

async def async_step_add_sensor(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
Expand Down Expand Up @@ -352,7 +368,7 @@ async def async_step_add_sensor(
async def async_step_choose_sensor(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the selection of a sensor."""
"""Choose a sensor."""
if user_input is None:
options = self._flow_data.pop(CONF_NEARBY_SENSOR_OPTIONS)
return self.async_show_form(
Expand All @@ -375,13 +391,13 @@ async def async_step_init(
"""Manage the options."""
return self.async_show_menu(
step_id="init",
menu_options=["add_sensor", "remove_sensor"],
menu_options=["add_sensor", "remove_sensor", "settings"],
)

async def async_step_remove_sensor(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Add a sensor."""
"""Remove a sensor."""
if user_input is None:
return self.async_show_form(
step_id="remove_sensor",
Expand Down Expand Up @@ -437,3 +453,15 @@ def async_device_entity_state_changed(_: Event) -> None:
options[CONF_SENSOR_INDICES].remove(removed_sensor_index)

return self.async_create_entry(data=options)

async def async_step_settings(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Manage settings."""
if user_input is None:
return self.async_show_form(
step_id="settings", data_schema=self.settings_schema
)

options = deepcopy({**self.config_entry.options})
return self.async_create_entry(data=options | user_input)
1 change: 1 addition & 0 deletions homeassistant/components/purpleair/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

CONF_READ_KEY = "read_key"
CONF_SENSOR_INDICES = "sensor_indices"
CONF_SHOW_ON_MAP = "show_on_map"
9 changes: 8 additions & 1 deletion homeassistant/components/purpleair/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@
"init": {
"menu_options": {
"add_sensor": "Add sensor",
"remove_sensor": "Remove sensor"
"remove_sensor": "Remove sensor",
"settings": "Settings"
}
},
"remove_sensor": {
Expand All @@ -90,6 +91,12 @@
"data_description": {
"sensor_device_id": "The sensor to remove"
}
},
"settings": {
"title": "Settings",
"data": {
"show_on_map": "Show configured sensor locations on the map"
}
}
},
"error": {
Expand Down
26 changes: 26 additions & 0 deletions tests/components/purpleair/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,29 @@ async def test_options_remove_sensor(
# Unload to make sure the update does not run after the
# mock is removed.
await hass.config_entries.async_unload(config_entry.entry_id)


async def test_options_settings(
hass: HomeAssistant, config_entry, setup_config_entry
) -> None:
"""Test setting settings via the options flow."""
result = await hass.config_entries.options.async_init(config_entry.entry_id)
assert result["type"] == data_entry_flow.FlowResultType.MENU
assert result["step_id"] == "init"

result = await hass.config_entries.options.async_configure(
result["flow_id"], user_input={"next_step_id": "settings"}
)
assert result["type"] == data_entry_flow.FlowResultType.FORM
assert result["step_id"] == "settings"

result = await hass.config_entries.options.async_configure(
result["flow_id"], user_input={"show_on_map": True}
)
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
assert result["data"] == {
"sensor_indices": [TEST_SENSOR_INDEX1],
"show_on_map": True,
}

assert config_entry.options["show_on_map"] is True