commit
076227acbe
|
@ -12,7 +12,7 @@ from homeassistant.const import (
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
|
@ -81,16 +81,11 @@ class AccuWeatherSensor(CoordinatorEntity, SensorEntity):
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
|
self._sensor_data = _get_sensor_data(coordinator.data, forecast_day, kind)
|
||||||
if forecast_day is None:
|
if forecast_day is None:
|
||||||
self._description = SENSOR_TYPES[kind]
|
self._description = SENSOR_TYPES[kind]
|
||||||
self._sensor_data: dict[str, Any]
|
|
||||||
if kind == "Precipitation":
|
|
||||||
self._sensor_data = coordinator.data["PrecipitationSummary"][kind]
|
|
||||||
else:
|
|
||||||
self._sensor_data = coordinator.data[kind]
|
|
||||||
else:
|
else:
|
||||||
self._description = FORECAST_SENSOR_TYPES[kind]
|
self._description = FORECAST_SENSOR_TYPES[kind]
|
||||||
self._sensor_data = coordinator.data[ATTR_FORECAST][forecast_day][kind]
|
|
||||||
self._unit_system = API_METRIC if coordinator.is_metric else API_IMPERIAL
|
self._unit_system = API_METRIC if coordinator.is_metric else API_IMPERIAL
|
||||||
self._name = name
|
self._name = name
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
|
@ -182,3 +177,24 @@ class AccuWeatherSensor(CoordinatorEntity, SensorEntity):
|
||||||
def entity_registry_enabled_default(self) -> bool:
|
def entity_registry_enabled_default(self) -> bool:
|
||||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||||
return self._description[ATTR_ENABLED]
|
return self._description[ATTR_ENABLED]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_coordinator_update(self) -> None:
|
||||||
|
"""Handle data update."""
|
||||||
|
self._sensor_data = _get_sensor_data(
|
||||||
|
self.coordinator.data, self.forecast_day, self.kind
|
||||||
|
)
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_sensor_data(
|
||||||
|
sensors: dict[str, Any], forecast_day: int | None, kind: str
|
||||||
|
) -> Any:
|
||||||
|
"""Get sensor data."""
|
||||||
|
if forecast_day is not None:
|
||||||
|
return sensors[ATTR_FORECAST][forecast_day][kind]
|
||||||
|
|
||||||
|
if kind == "Precipitation":
|
||||||
|
return sensors["PrecipitationSummary"][kind]
|
||||||
|
|
||||||
|
return sensors[kind]
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "Daikin AC",
|
"name": "Daikin AC",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/daikin",
|
"documentation": "https://www.home-assistant.io/integrations/daikin",
|
||||||
"requirements": ["pydaikin==2.4.2"],
|
"requirements": ["pydaikin==2.4.3"],
|
||||||
"codeowners": ["@fredrike"],
|
"codeowners": ["@fredrike"],
|
||||||
"zeroconf": ["_dkapi._tcp.local."],
|
"zeroconf": ["_dkapi._tcp.local."],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
|
|
|
@ -160,7 +160,7 @@ def handle_push_notification_channel(hass, connection, msg):
|
||||||
registered_channels = hass.data[DOMAIN][DATA_PUSH_CHANNEL]
|
registered_channels = hass.data[DOMAIN][DATA_PUSH_CHANNEL]
|
||||||
|
|
||||||
if webhook_id in registered_channels:
|
if webhook_id in registered_channels:
|
||||||
registered_channels.pop(webhook_id)()
|
registered_channels.pop(webhook_id)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def forward_push_notification(data):
|
def forward_push_notification(data):
|
||||||
|
|
|
@ -153,8 +153,8 @@ class OmniLogicPumpControl(OmniLogicSwitch):
|
||||||
state_key=state_key,
|
state_key=state_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
self._max_speed = int(coordinator.data[item_id]["Max-Pump-Speed"])
|
self._max_speed = int(coordinator.data[item_id].get("Max-Pump-Speed", 100))
|
||||||
self._min_speed = int(coordinator.data[item_id]["Min-Pump-Speed"])
|
self._min_speed = int(coordinator.data[item_id].get("Min-Pump-Speed", 0))
|
||||||
|
|
||||||
if "Filter-Type" in coordinator.data[item_id]:
|
if "Filter-Type" in coordinator.data[item_id]:
|
||||||
self._pump_type = PUMP_TYPES[coordinator.data[item_id]["Filter-Type"]]
|
self._pump_type = PUMP_TYPES[coordinator.data[item_id]["Filter-Type"]]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"domain": "rfxtrx",
|
"domain": "rfxtrx",
|
||||||
"name": "RFXCOM RFXtrx",
|
"name": "RFXCOM RFXtrx",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/rfxtrx",
|
"documentation": "https://www.home-assistant.io/integrations/rfxtrx",
|
||||||
"requirements": ["pyRFXtrx==0.26.1"],
|
"requirements": ["pyRFXtrx==0.27.0"],
|
||||||
"codeowners": ["@danielhiversen", "@elupus", "@RobBie1221"],
|
"codeowners": ["@danielhiversen", "@elupus", "@RobBie1221"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"iot_class": "local_push"
|
"iot_class": "local_push"
|
||||||
|
|
|
@ -382,6 +382,14 @@ class SonosSpeaker:
|
||||||
"""Update device properties from an event."""
|
"""Update device properties from an event."""
|
||||||
if more_info := event.variables.get("more_info"):
|
if more_info := event.variables.get("more_info"):
|
||||||
battery_dict = dict(x.split(":") for x in more_info.split(","))
|
battery_dict = dict(x.split(":") for x in more_info.split(","))
|
||||||
|
if "BattChg" not in battery_dict:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"Unknown device properties update for %s (%s), please report an issue: '%s'",
|
||||||
|
self.zone_name,
|
||||||
|
self.model_name,
|
||||||
|
more_info,
|
||||||
|
)
|
||||||
|
return
|
||||||
await self.async_update_battery_info(battery_dict)
|
await self.async_update_battery_info(battery_dict)
|
||||||
self.async_write_entity_states()
|
self.async_write_entity_states()
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ class WhoisSensor(SensorEntity):
|
||||||
expiration_date = response["expiration_date"]
|
expiration_date = response["expiration_date"]
|
||||||
if isinstance(expiration_date, list):
|
if isinstance(expiration_date, list):
|
||||||
attrs[ATTR_EXPIRES] = expiration_date[0].isoformat()
|
attrs[ATTR_EXPIRES] = expiration_date[0].isoformat()
|
||||||
|
expiration_date = expiration_date[0]
|
||||||
else:
|
else:
|
||||||
attrs[ATTR_EXPIRES] = expiration_date.isoformat()
|
attrs[ATTR_EXPIRES] = expiration_date.isoformat()
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from typing import Final
|
||||||
|
|
||||||
MAJOR_VERSION: Final = 2021
|
MAJOR_VERSION: Final = 2021
|
||||||
MINOR_VERSION: Final = 6
|
MINOR_VERSION: Final = 6
|
||||||
PATCH_VERSION: Final = "5"
|
PATCH_VERSION: Final = "6"
|
||||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
||||||
|
|
|
@ -1253,7 +1253,7 @@ pyMetEireann==0.2
|
||||||
pyMetno==0.8.3
|
pyMetno==0.8.3
|
||||||
|
|
||||||
# homeassistant.components.rfxtrx
|
# homeassistant.components.rfxtrx
|
||||||
pyRFXtrx==0.26.1
|
pyRFXtrx==0.27.0
|
||||||
|
|
||||||
# homeassistant.components.switchmate
|
# homeassistant.components.switchmate
|
||||||
# pySwitchmate==0.4.6
|
# pySwitchmate==0.4.6
|
||||||
|
@ -1352,7 +1352,7 @@ pycsspeechtts==1.0.4
|
||||||
# pycups==1.9.73
|
# pycups==1.9.73
|
||||||
|
|
||||||
# homeassistant.components.daikin
|
# homeassistant.components.daikin
|
||||||
pydaikin==2.4.2
|
pydaikin==2.4.3
|
||||||
|
|
||||||
# homeassistant.components.danfoss_air
|
# homeassistant.components.danfoss_air
|
||||||
pydanfossair==0.1.0
|
pydanfossair==0.1.0
|
||||||
|
|
|
@ -693,7 +693,7 @@ pyMetEireann==0.2
|
||||||
pyMetno==0.8.3
|
pyMetno==0.8.3
|
||||||
|
|
||||||
# homeassistant.components.rfxtrx
|
# homeassistant.components.rfxtrx
|
||||||
pyRFXtrx==0.26.1
|
pyRFXtrx==0.27.0
|
||||||
|
|
||||||
# homeassistant.components.tibber
|
# homeassistant.components.tibber
|
||||||
pyTibber==0.17.0
|
pyTibber==0.17.0
|
||||||
|
@ -747,7 +747,7 @@ pycomfoconnect==0.4
|
||||||
pycoolmasternet-async==0.1.2
|
pycoolmasternet-async==0.1.2
|
||||||
|
|
||||||
# homeassistant.components.daikin
|
# homeassistant.components.daikin
|
||||||
pydaikin==2.4.2
|
pydaikin==2.4.3
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==79
|
pydeconz==79
|
||||||
|
|
|
@ -673,3 +673,36 @@ async def test_sensor_imperial_units(hass):
|
||||||
assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION
|
assert state.attributes.get(ATTR_ATTRIBUTION) == ATTRIBUTION
|
||||||
assert state.attributes.get(ATTR_ICON) == "mdi:weather-fog"
|
assert state.attributes.get(ATTR_ICON) == "mdi:weather-fog"
|
||||||
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == LENGTH_FEET
|
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == LENGTH_FEET
|
||||||
|
|
||||||
|
|
||||||
|
async def test_state_update(hass):
|
||||||
|
"""Ensure the sensor state changes after updating the data."""
|
||||||
|
await init_integration(hass)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.home_cloud_ceiling")
|
||||||
|
assert state
|
||||||
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
assert state.state == "3200"
|
||||||
|
|
||||||
|
future = utcnow() + timedelta(minutes=60)
|
||||||
|
|
||||||
|
current_condition = json.loads(
|
||||||
|
load_fixture("accuweather/current_conditions_data.json")
|
||||||
|
)
|
||||||
|
current_condition["Ceiling"]["Metric"]["Value"] = 3300
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.accuweather.AccuWeather.async_get_current_conditions",
|
||||||
|
return_value=current_condition,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.accuweather.AccuWeather.requests_remaining",
|
||||||
|
new_callable=PropertyMock,
|
||||||
|
return_value=10,
|
||||||
|
):
|
||||||
|
async_fire_time_changed(hass, future)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.home_cloud_ceiling")
|
||||||
|
assert state
|
||||||
|
assert state.state != STATE_UNAVAILABLE
|
||||||
|
assert state.state == "3300"
|
||||||
|
|
|
@ -136,6 +136,18 @@ async def test_notify_ws_works(
|
||||||
sub_result = await client.receive_json()
|
sub_result = await client.receive_json()
|
||||||
assert sub_result["success"]
|
assert sub_result["success"]
|
||||||
|
|
||||||
|
# Subscribe twice, it should forward all messages to 2nd subscription
|
||||||
|
await client.send_json(
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"type": "mobile_app/push_notification_channel",
|
||||||
|
"webhook_id": "mock-webhook_id",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
sub_result = await client.receive_json()
|
||||||
|
assert sub_result["success"]
|
||||||
|
|
||||||
assert await hass.services.async_call(
|
assert await hass.services.async_call(
|
||||||
"notify", "mobile_app_test", {"message": "Hello world"}, blocking=True
|
"notify", "mobile_app_test", {"message": "Hello world"}, blocking=True
|
||||||
)
|
)
|
||||||
|
@ -144,13 +156,14 @@ async def test_notify_ws_works(
|
||||||
|
|
||||||
msg_result = await client.receive_json()
|
msg_result = await client.receive_json()
|
||||||
assert msg_result["event"] == {"message": "Hello world"}
|
assert msg_result["event"] == {"message": "Hello world"}
|
||||||
|
assert msg_result["id"] == 6 # This is the new subscription
|
||||||
|
|
||||||
# Unsubscribe, now it should go over http
|
# Unsubscribe, now it should go over http
|
||||||
await client.send_json(
|
await client.send_json(
|
||||||
{
|
{
|
||||||
"id": 6,
|
"id": 7,
|
||||||
"type": "unsubscribe_events",
|
"type": "unsubscribe_events",
|
||||||
"subscription": 5,
|
"subscription": 6,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
sub_result = await client.receive_json()
|
sub_result = await client.receive_json()
|
||||||
|
@ -165,7 +178,7 @@ async def test_notify_ws_works(
|
||||||
# Test non-existing webhook ID
|
# Test non-existing webhook ID
|
||||||
await client.send_json(
|
await client.send_json(
|
||||||
{
|
{
|
||||||
"id": 7,
|
"id": 8,
|
||||||
"type": "mobile_app/push_notification_channel",
|
"type": "mobile_app/push_notification_channel",
|
||||||
"webhook_id": "non-existing",
|
"webhook_id": "non-existing",
|
||||||
}
|
}
|
||||||
|
@ -180,7 +193,7 @@ async def test_notify_ws_works(
|
||||||
# Test webhook ID linked to other user
|
# Test webhook ID linked to other user
|
||||||
await client.send_json(
|
await client.send_json(
|
||||||
{
|
{
|
||||||
"id": 8,
|
"id": 9,
|
||||||
"type": "mobile_app/push_notification_channel",
|
"type": "mobile_app/push_notification_channel",
|
||||||
"webhook_id": "webhook_id_2",
|
"webhook_id": "webhook_id_2",
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ async def test_fire_event(hass, rfxtrx):
|
||||||
"type_string": "Byron SX",
|
"type_string": "Byron SX",
|
||||||
"id_string": "00:90",
|
"id_string": "00:90",
|
||||||
"data": "0716000100900970",
|
"data": "0716000100900970",
|
||||||
"values": {"Command": "Chime", "Rssi numeric": 7, "Sound": 9},
|
"values": {"Command": "Sound 9", "Rssi numeric": 7, "Sound": 9},
|
||||||
"device_id": device_id_2.id,
|
"device_id": device_id_2.id,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -83,3 +83,23 @@ async def test_battery_on_S1(hass, config_entry, config, soco, battery_event):
|
||||||
power_state = hass.states.get(power.entity_id)
|
power_state = hass.states.get(power.entity_id)
|
||||||
assert power_state.state == STATE_OFF
|
assert power_state.state == STATE_OFF
|
||||||
assert power_state.attributes.get(ATTR_BATTERY_POWER_SOURCE) == "BATTERY"
|
assert power_state.attributes.get(ATTR_BATTERY_POWER_SOURCE) == "BATTERY"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_device_payload_without_battery(
|
||||||
|
hass, config_entry, config, soco, battery_event, caplog
|
||||||
|
):
|
||||||
|
"""Test device properties event update without battery info."""
|
||||||
|
soco.get_battery_info.return_value = None
|
||||||
|
|
||||||
|
await setup_platform(hass, config_entry, config)
|
||||||
|
|
||||||
|
subscription = soco.deviceProperties.subscribe.return_value
|
||||||
|
sub_callback = subscription.callback
|
||||||
|
|
||||||
|
bad_payload = "BadKey:BadValue"
|
||||||
|
battery_event.variables["more_info"] = bad_payload
|
||||||
|
|
||||||
|
sub_callback(battery_event)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert bad_payload in caplog.text
|
||||||
|
|
Loading…
Reference in New Issue