core icon indicating copy to clipboard operation
core copied to clipboard

Add WeatherFlow integration

Open jeeftor opened this issue 2 years ago β€’ 33 comments

Proposed change

@natekspencer created a HACS Integration for the WeatherFlow tempest weather station. I've decided to migrate his code over into an official integration (with his permission).

This implements a single platform PLATFORM.SENSOR which will display just about the entire swatch of available data. It uses a backing library to gather this data via UDP from the base station. Weather flow puts out UDP documentation so this would be a semi-official integration I guess as the API is published.

Reference Material

  • https://weatherflow.github.io/Tempest/api/udp.html
  • https://github.com/briis/pyweatherflowudp
image

Type of change

  • [ ] Dependency upgrade
  • [ ] Bugfix (non-breaking change which fixes an issue)
  • [x] New integration (thank you!)
  • [ ] New feature (which adds functionality to an existing integration)
  • [ ] Deprecation (breaking change to happen in the future)
  • [ ] Breaking change (fix/feature causing existing functionality to break)
  • [ ] Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request: https://github.com/home-assistant/home-assistant.io/pull/23478

Checklist

  • [x] The code change is tested and works locally.
  • [x] Local tests pass. Your PR cannot be merged unless tests pass
  • [x] There is no commented out code in this PR.
  • [x] I have followed the development checklist
  • [x] The code has been formatted using Black (black --fast homeassistant tests)
  • [x] Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • [x] The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • [x] New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • [ ] For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.
  • [x] Untested files have been added to .coveragerc.

The integration reached or maintains the following Integration Quality Scale:

  • [x] No score or internal
  • [ ] πŸ₯ˆ Silver
  • [ ] πŸ₯‡ Gold
  • [ ] πŸ† Platinum

To help with the load of incoming pull requests:

jeeftor avatar Jul 20 '22 20:07 jeeftor

And the wait continues... but that's ok :) ....

jeeftor avatar Aug 25 '22 12:08 jeeftor

@jeeftor Please don't ping for reviews. That is not acceptable or wished for. And to make it actually not work, I generally skip PRs that actually ping/ask.

frenck avatar Sep 15 '22 15:09 frenck

Apologies

jeeftor avatar Sep 15 '22 15:09 jeeftor

@natekspencer - did you make updates recently I need to pull in?

jeeftor avatar Nov 03 '22 18:11 jeeftor

You might want to disable wind speed and wind direction by default as they are updated 20 times per minute. The wind average and wind direction average are updated once per minute like the other sensors.

Edit: corrected typo

lymanepp avatar Dec 01 '22 16:12 lymanepp

You might want to disable wind speed and wind direction by default as they are updated 20 times per second. The wind average and wind direction average are updated once per minute like the other sensors.

It's actually around 20 times per minute (every 3 seconds). While still frequent, I would argue that it's one of the more relevant sensors.

natekspencer avatar Dec 01 '22 16:12 natekspencer

It's actually around 20 times per minute (every 3 seconds). While still frequent, I would argue that it's one of the more relevant sensors.

Oops, typo. Corrected. Thanks for catching. But it's still a valid question as those two sensors accounted for around half of all data in my HA database.

lymanepp avatar Dec 01 '22 16:12 lymanepp

It's actually around 20 times per minute (every 3 seconds). While still frequent, I would argue that it's one of the more relevant sensors.

Oops, typo. Corrected. Thanks for catching. But it's still a valid question as those two sensors accounted for around half of all data in my HA database.

Yeah, agreed. Wind direction for me is less relevant. But wind speed is crucial. Sometimes a minute delay is too long and can cause serious damage. I get frequent wind which can spike very quickly. Being able to react to the first such spike is important as a full minute of sustained high winds can be disastrous. I guess the question is, should it be disabled by default with a note saying to enable it if you need it. Or should it be enabled by default with a note saying it may cause a large HA database and disable if unneeded?

natekspencer avatar Dec 01 '22 16:12 natekspencer

But wind speed is crucial. Sometimes a minute delay is too long and can cause serious damage. I get frequent wind which can spike very quickly. Being able to react to the first such spike is important as a full minute of sustained high winds can be disastrous.

It would be nice to be able to use the data for automations without being stored. Or maybe have a different retention period.

lymanepp avatar Dec 01 '22 18:12 lymanepp

It would be nice to be able to use the data for automations without being stored. Or maybe have a different retention period.

True. The immediate value is wonderful for automations. After that, I only really care about the statistics of it and don't need the rest of the granularity.

natekspencer avatar Dec 01 '22 18:12 natekspencer

Well this has been open for some time now ... I'm hoping somebody will take a look at it finally....

jeeftor avatar Dec 07 '22 12:12 jeeftor

Well this has been open for some time now ... I'm hoping somebody will take a look at it finally....

Working well for several months now, if that positive data point helps.

HyperActiveJ avatar Dec 08 '22 21:12 HyperActiveJ

@HyperActiveJ - Are you running the HACS version ... This would be an official version... and it would eventually move out of HACS - making it more widely available to the "slightly less nerdy" folks who just install vanilla HA

jeeftor avatar Dec 08 '22 21:12 jeeftor

@HyperActiveJ - Are you running the HACS version ... This would be an official version... and it would eventually move out of HACS - making it more widely available to the "slightly less nerdy" folks who just install vanilla HA

Understood, I've just been pulling source from your repo.

HyperActiveJ avatar Dec 08 '22 21:12 HyperActiveJ

I commend your patience getting this integrated into HA. But it's sad that the dev team continues to ignore this contribution. πŸ™„

lymanepp avatar Jan 17 '23 15:01 lymanepp

I wonder if we should just include a couple of sensors (like temperature and humidity) initially to reduce the code needed to review.

natekspencer avatar Jan 17 '23 17:01 natekspencer

I wonder if we should just include a couple of sensors (like temperature and humidity) initially to reduce the code needed to review.

The HA component is less than 600 lines of code, so I don't see that as much of an impediment. Maybe WeatherFlow could donate a Tempest device to one of the devs. πŸ˜‚

lymanepp avatar Jan 17 '23 17:01 lymanepp

I wonder if we should just include a couple of sensors (like temperature and humidity) initially to reduce the code needed to review.

The HA component is less than 600 lines of code, so I don't see that as much of an impediment. Maybe WeatherFlow could donate a Tempest device to one of the devs. πŸ˜‚

Just hypothesizing options, haha

natekspencer avatar Jan 17 '23 17:01 natekspencer

I wonder if we should just include a couple of sensors (like temperature and humidity) initially to reduce the code needed to review.

The HA component is less than 600 lines of code, so I don't see that as much of an impediment. Maybe WeatherFlow could donate a Tempest device to one of the devs. πŸ˜‚

Just hypothesizing options, haha

I'm all for it if it would help.

lymanepp avatar Jan 17 '23 17:01 lymanepp

The attached patch contains required changes for recently deprecated things. weatherflow.patch

lymanepp avatar Jan 17 '23 20:01 lymanepp

I wonder if we should just include a couple of sensors (like temperature and humidity) initially to reduce the code needed to review.

The HA component is less than 600 lines of code, so I don't see that as much of an impediment. Maybe WeatherFlow could donate a Tempest device to one of the devs. πŸ˜‚

Just hypothesizing options, haha

I'm all for it if it would help.

At least the documentation component got reviewed.... so maybe there's hope! :)

jeeftor avatar Jan 19 '23 13:01 jeeftor

I just discovered WeatherFlow and don’t have HACS currently so I’m in that niche that would like to see this merged. Maybe the CI check failures are holding this back? Sorting the manifest keys for hassfest and addressing the TODO for pylint seems fairly straightforward. The mypy and ruff errors are less clear (to me). I do not have a device to test with or I’d try to help with the changes myself.

michaelcresswell avatar Feb 24 '23 20:02 michaelcresswell

It would be nice to be able to use the data for automations without being stored. Or maybe have a different retention period.

I found that it's possible to prevent recording selected values. This leaves them available to use for automations.

# https://www.home-assistant.io/integrations/recorder/
recorder:
  exclude:
    entity_globs:
      - sensor.outdoor_wind_speed
      - sensor.outdoor_wind_direction

lymanepp avatar Feb 25 '23 00:02 lymanepp

I've marked this PR, as some jobs in our CI are failing. Please check the output of those jobs to see what went wrong and adjust the PR accordingly.

Please un-draft it once the CI passes and it is ready for review again by clicking the "Ready for review" button.

Thanks! πŸ‘

../Frenck

Learn more about our pull request process.

frenck avatar Mar 06 '23 11:03 frenck

I've marked this PR, as some jobs in our CI are failing. Please check the output of those jobs to see what went wrong and adjust the PR accordingly.

Here are fixes for most (all?) of the CI failures. Not that these are due to recent changes in the HA builds as the CIs were previously passing.

diff --git a/homeassistant/components/weatherflow/manifest.json b/homeassistant/components/weatherflow/manifest.json
index 1274c1ff22..42ab4dc6e7 100644
--- a/homeassistant/components/weatherflow/manifest.json
+++ b/homeassistant/components/weatherflow/manifest.json
@@ -1,15 +1,15 @@
 {
   "domain": "weatherflow",
   "name": "WeatherFlow",
+  "codeowners": ["@natekspencer", "@jeeftor"],
   "config_flow": true,
+  "dependencies": [],
   "documentation": "https://www.home-assistant.io/integrations/weatherflow",
-  "requirements": ["pyweatherflowudp==1.4.1"],
-  "ssdp": [],
-  "zeroconf": [],
   "homekit": {},
-  "dependencies": [],
-  "codeowners": ["@natekspencer", "@jeeftor"],
-  "iot_class": "local_push",
   "integration_type": "hub",
-  "loggers": ["pyweatherflowudp"]
+  "iot_class": "local_push",
+  "loggers": ["pyweatherflowudp"],
+  "requirements": ["pyweatherflowudp==1.4.1"],
+  "ssdp": [],
+  "zeroconf": []
 }
diff --git a/homeassistant/components/weatherflow/sensor.py b/homeassistant/components/weatherflow/sensor.py
index 2c7dfeb45f..3801888635 100644
--- a/homeassistant/components/weatherflow/sensor.py
+++ b/homeassistant/components/weatherflow/sensor.py
@@ -37,9 +37,10 @@ from homeassistant.const import (
     UnitOfTemperature,
     UnitOfVolumetricFlux,
 )
+from homeassistant.const import EntityCategory
 from homeassistant.core import HomeAssistant, callback
 from homeassistant.helpers.dispatcher import async_dispatcher_connect
-from homeassistant.helpers.entity import DeviceInfo, EntityCategory
+from homeassistant.helpers.entity import DeviceInfo
 from homeassistant.helpers.entity_platform import AddEntitiesCallback
 from homeassistant.helpers.typing import StateType
 from homeassistant.util.unit_system import METRIC_SYSTEM
@@ -49,9 +50,6 @@ from .const import DOMAIN, LOGGER
 CONCENTRATION_KILOGRAMS_PER_CUBIC_METER = "kg/mΒ³"
 CONCENTRATION_POUNDS_PER_CUBIC_FOOT = "lbs/ftΒ³"
 
-# TODO: Replace with UnitOfSpeed.KILOMETERS_PER_HOUR (km/h)?
-QUANTITY_KILOMETERS_PER_HOUR = "kph"
-
 IMPERIAL_UNIT_MAP = {
     CONCENTRATION_KILOGRAMS_PER_CUBIC_METER: CONCENTRATION_POUNDS_PER_CUBIC_FOOT,
     UnitOfLength.KILOMETERS: UnitOfLength.MILES,
@@ -96,7 +94,7 @@ class WeatherFlowWindSensorEntityDescription(WeatherFlowSensorEntityDescription)
         self.state_class = SensorStateClass.MEASUREMENT
         self.conversion_fn = lambda attr: attr.to(UnitOfSpeed.MILES_PER_HOUR)
         self.decimals = 2
-        self.value_fn = lambda attr: attr.to(QUANTITY_KILOMETERS_PER_HOUR)
+        self.value_fn = lambda attr: attr.to(UnitOfSpeed.KILOMETERS_PER_HOUR)
 
 
 SENSORS: tuple[WeatherFlowSensorEntityDescription, ...] = (
diff --git a/tests/components/weatherflow/conftest.py b/tests/components/weatherflow/conftest.py
index e1c7e3dbcc..3ed71b225e 100644
--- a/tests/components/weatherflow/conftest.py
+++ b/tests/components/weatherflow/conftest.py
@@ -25,19 +25,19 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]:
         yield mock_setup
 
 
[email protected]()
[email protected]
 def mock_config_entry() -> MockConfigEntry:
     """Return a mock config entry."""
     return MockConfigEntry(domain=DOMAIN, data={CONF_HOST: "1.2.3.4"})
 
 
[email protected]()
[email protected]
 def mock_config_entry2() -> MockConfigEntry:
     """Return a mock config entry."""
     return MockConfigEntry(domain=DOMAIN, data={CONF_HOST: DEFAULT_HOST})
 
 
[email protected]()
[email protected]
 def mock_has_devices() -> Generator[AsyncMock, None, None]:
     """Return a mock has_devices function."""
     with patch(
@@ -47,7 +47,7 @@ def mock_has_devices() -> Generator[AsyncMock, None, None]:
         yield mock_has_devices
 
 
[email protected]()
[email protected]
 def mock_has_no_devices() -> Generator[AsyncMock, None, None]:
     """Return a mock has_devices function returning False."""
     with patch(
@@ -57,7 +57,7 @@ def mock_has_no_devices() -> Generator[AsyncMock, None, None]:
         yield mock_has_devices
 
 
[email protected]()
[email protected]
 def mock_has_devices_error_listener() -> Generator[AsyncMock, None, None]:
     """Return a mock has_devices returning an error."""
     with patch(
@@ -67,7 +67,7 @@ def mock_has_devices_error_listener() -> Generator[AsyncMock, None, None]:
         yield mock_has_devices
 
 
[email protected]()
[email protected]
 def mock_has_devices_error_address_in_use() -> Generator[AsyncMock, None, None]:
     """Return a mock has_devices returning an error."""
     with patch(
@@ -77,7 +77,7 @@ def mock_has_devices_error_address_in_use() -> Generator[AsyncMock, None, None]:
         yield mock_has_devices
 
 
[email protected]()
[email protected]
 def mock_stop() -> Generator[AsyncMock, None, None]:
     """Return a fixture to handle the stop of udp."""
 
@@ -92,7 +92,7 @@ def mock_stop() -> Generator[AsyncMock, None, None]:
         yield mock_function
 
 
[email protected]()
[email protected]
 def mock_start() -> Generator[AsyncMock, None, None]:
     """Return fixture for starting upd."""
     DEVICE_JSON = """
@@ -122,7 +122,7 @@ def mock_start() -> Generator[AsyncMock, None, None]:
         """Mock listening function."""
         self._devices["HB-00000001"] = device
         self._udp_task = asyncio.create_task(device_discovery_task(self))
-        self._udp_task.add_done_callback(lambda _: print("Done Callback"))
+        self._udp_task.add_done_callback(lambda _: print("Done Callback"))  # noqa: T201
 
     with patch(
         "pyweatherflowudp.client.WeatherFlowListener.start_listening",
@@ -132,7 +132,7 @@ def mock_start() -> Generator[AsyncMock, None, None]:
         yield mock_function
 
 
[email protected]()
[email protected]
 def mock_start_timeout() -> Generator[AsyncMock, None, None]:
     """Return fixture for starting upd."""
 
diff --git a/tests/components/weatherflow/test_config_flow.py b/tests/components/weatherflow/test_config_flow.py
index 0433c285f4..254e971346 100644
--- a/tests/components/weatherflow/test_config_flow.py
+++ b/tests/components/weatherflow/test_config_flow.py
@@ -129,7 +129,7 @@ async def test_devices_with_mocks_timeout(
         await asyncio.sleep(1)
 
     # Start the time forarder task
-    asyncio.create_task(time_jump(hass))
+    _ = asyncio.create_task(time_jump(hass))
 
     result = await hass.config_entries.flow.async_init(
         DOMAIN,

lymanepp avatar Mar 07 '23 02:03 lymanepp

If I cant get to this today -> I'll be able to get to it in a weeks time...

jeeftor avatar Mar 17 '23 19:03 jeeftor

It would be nice to be able to use the data for automations without being stored. Or maybe have a different retention period.

I found that it's possible to prevent recording selected values. This leaves them available to use for automations.

# https://www.home-assistant.io/integrations/recorder/
recorder:
  exclude:
    entity_globs:
      - sensor.outdoor_wind_speed
      - sensor.outdoor_wind_direction

Is this something that should go in the docs ... or - just let somebody figure it out later :)

jeeftor avatar Mar 17 '23 19:03 jeeftor

Just the docs...

On Fri, Mar 17, 2023, 3:21 PM Jeef @.***> wrote:

It would be nice to be able to use the data for automations without being stored. Or maybe have a different retention period.

I found that it's possible to prevent recording selected values. This leaves them available to use for automations.

https://www.home-assistant.io/integrations/recorder/

recorder: exclude: entity_globs: - sensor.outdoor_wind_speed - sensor.outdoor_wind_direction

Is this something that should go in the docs ... or - just let somebody figure it out later :)

β€” Reply to this email directly, view it on GitHub https://github.com/home-assistant/core/pull/75530#issuecomment-1474301021, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABAAJR5AKKIE4EK5LRPO7ZLW4S2SJANCNFSM54FCHV6Q . You are receiving this because you are subscribed to this thread.Message ID: @.***>

lymanepp avatar Mar 17 '23 19:03 lymanepp

Looks like I got the final test passing... so Hopefully we're in good shape now.

jeeftor avatar Mar 17 '23 21:03 jeeftor

oh wow :) this looks very promising. do we have an idea in which release this could make it?

stefanschaedeli avatar Apr 13 '23 10:04 stefanschaedeli