core/homeassistant/components/magicseaweed/sensor.py

193 lines
6.1 KiB
Python
Raw Normal View History

"""Support for magicseaweed data from magicseaweed.com."""
from datetime import timedelta
import logging
import magicseaweed
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
ATTR_ATTRIBUTION,
2019-07-31 19:25:30 +00:00
CONF_API_KEY,
CONF_MONITORED_CONDITIONS,
CONF_NAME,
2019-07-31 19:25:30 +00:00
)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
import homeassistant.util.dt as dt_util
_LOGGER = logging.getLogger(__name__)
2019-07-31 19:25:30 +00:00
CONF_HOURS = "hours"
CONF_SPOT_ID = "spot_id"
CONF_UNITS = "units"
2019-07-31 19:25:30 +00:00
DEFAULT_UNIT = "us"
DEFAULT_NAME = "MSW"
DEFAULT_ATTRIBUTION = "Data provided by magicseaweed.com"
2019-07-31 19:25:30 +00:00
ICON = "mdi:waves"
2019-07-31 19:25:30 +00:00
HOURS = ["12AM", "3AM", "6AM", "9AM", "12PM", "3PM", "6PM", "9PM"]
SENSOR_TYPES = {
2019-07-31 19:25:30 +00:00
"max_breaking_swell": ["Max"],
"min_breaking_swell": ["Min"],
"swell_forecast": ["Forecast"],
}
2019-07-31 19:25:30 +00:00
UNITS = ["eu", "uk", "us"]
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_MONITORED_CONDITIONS): vol.All(
cv.ensure_list, [vol.In(SENSOR_TYPES)]
),
vol.Required(CONF_API_KEY): cv.string,
vol.Required(CONF_SPOT_ID): vol.All(cv.ensure_list, [cv.string]),
vol.Optional(CONF_HOURS, default=None): vol.All(
cv.ensure_list, [vol.In(HOURS)]
),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_UNITS): vol.In(UNITS),
}
)
# Return cached results if last scan was less then this time ago.
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Magicseaweed sensor."""
name = config.get(CONF_NAME)
spot_id = config[CONF_SPOT_ID]
api_key = config[CONF_API_KEY]
hours = config.get(CONF_HOURS)
if CONF_UNITS in config:
units = config.get(CONF_UNITS)
elif hass.config.units.is_metric:
units = UNITS[0]
else:
units = UNITS[2]
2019-07-31 19:25:30 +00:00
forecast_data = MagicSeaweedData(api_key=api_key, spot_id=spot_id, units=units)
forecast_data.update()
# If connection failed don't setup platform.
if forecast_data.currently is None or forecast_data.hourly is None:
return
sensors = []
for variable in config[CONF_MONITORED_CONDITIONS]:
2019-07-31 19:25:30 +00:00
sensors.append(MagicSeaweedSensor(forecast_data, variable, name, units))
if "forecast" not in variable and hours is not None:
for hour in hours:
2019-07-31 19:25:30 +00:00
sensors.append(
MagicSeaweedSensor(forecast_data, variable, name, units, hour)
)
add_entities(sensors, True)
class MagicSeaweedSensor(Entity):
"""Implementation of a MagicSeaweed sensor."""
2019-07-31 19:25:30 +00:00
def __init__(self, forecast_data, sensor_type, name, unit_system, hour=None):
"""Initialize the sensor."""
self.client_name = name
self.data = forecast_data
self.hour = hour
self.type = sensor_type
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
self._name = SENSOR_TYPES[sensor_type][0]
self._icon = None
self._state = None
self._unit_system = unit_system
self._unit_of_measurement = None
@property
def name(self):
"""Return the name of the sensor."""
2019-07-31 19:25:30 +00:00
if self.hour is None and "forecast" in self.type:
return f"{self.client_name} {self._name}"
if self.hour is None:
return f"Current {self.client_name} {self._name}"
return f"{self.hour} {self.client_name} {self._name}"
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def unit_system(self):
"""Return the unit system of this entity."""
return self._unit_system
@property
def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement
@property
def icon(self):
"""Return the entity weather icon, if any."""
return ICON
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attrs
def update(self):
"""Get the latest data from Magicseaweed and updates the states."""
self.data.update()
if self.hour is None:
forecast = self.data.currently
else:
forecast = self.data.hourly[self.hour]
self._unit_of_measurement = forecast.swell_unit
2019-07-31 19:25:30 +00:00
if self.type == "min_breaking_swell":
self._state = forecast.swell_minBreakingHeight
2019-07-31 19:25:30 +00:00
elif self.type == "max_breaking_swell":
self._state = forecast.swell_maxBreakingHeight
2019-07-31 19:25:30 +00:00
elif self.type == "swell_forecast":
summary = f"{forecast.swell_minBreakingHeight} - {forecast.swell_maxBreakingHeight}"
self._state = summary
if self.hour is None:
for hour, data in self.data.hourly.items():
occurs = hour
hr_summary = f"{data.swell_minBreakingHeight} - {data.swell_maxBreakingHeight} {data.swell_unit}"
self._attrs[occurs] = hr_summary
2019-07-31 19:25:30 +00:00
if self.type != "swell_forecast":
self._attrs.update(forecast.attrs)
class MagicSeaweedData:
"""Get the latest data from MagicSeaweed."""
def __init__(self, api_key, spot_id, units):
"""Initialize the data object."""
2019-07-31 19:25:30 +00:00
self._msw = magicseaweed.MSW_Forecast(api_key, spot_id, None, units)
self.currently = None
self.hourly = {}
# Apply throttling to methods using configured interval
self.update = Throttle(MIN_TIME_BETWEEN_UPDATES)(self._update)
def _update(self):
"""Get the latest data from MagicSeaweed."""
try:
forecasts = self._msw.get_future()
self.currently = forecasts.data[0]
for forecast in forecasts.data[:8]:
2019-07-31 19:25:30 +00:00
hour = dt_util.utc_from_timestamp(forecast.localTimestamp).strftime(
"%-I%p"
)
self.hourly[hour] = forecast
except ConnectionError:
_LOGGER.error("Unable to retrieve data from Magicseaweed")