From 57fbbe462788d8916d11af4fd360eb917c22d6c9 Mon Sep 17 00:00:00 2001 From: Cyberes Date: Sun, 18 Aug 2024 15:38:47 -0600 Subject: [PATCH] add 24 hr max scales, improve readmes, reorganize pred card layout --- README.md | 59 +------ custom-component/README.md | 4 + custom-component/space_weather/sensor.py | 21 ++- dashboard/README.md | 17 ++ dashboard/www/space-weather-24hr-max-card.js | 157 ++++++++++++++++++ dashboard/www/space-weather-card.js | 2 +- dashboard/www/space-weather-pred-card.js | 18 +- feeder-mqtt/README.md | 56 +++++++ ...c.service => space-weather-feeder.service} | 2 +- 9 files changed, 262 insertions(+), 74 deletions(-) create mode 100644 custom-component/README.md create mode 100644 dashboard/README.md create mode 100644 dashboard/www/space-weather-24hr-max-card.js create mode 100644 feeder-mqtt/README.md rename feeder-mqtt/{vtec.service => space-weather-feeder.service} (60%) diff --git a/README.md b/README.md index 911c914..ee33aa4 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,5 @@ -# ha-noaa-space-weather-sensor +# ha-noaa-space-weather -*MQTT sensor to send NOAA space weather data to Home Assistant.* +*NOAA space weather data in Home Assistant.* -## Install - -1. Create an account at -2. `pip install -r requirements.txt` -3. `sudo apt install p7zip-full` - -### Google Chrome - -If you don't have Google Chrome installed (used to log into the NASA site), here's how to install it. - -```shell -wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -apt install ./google-chrome-stable_current_amd64.deb -``` - -## Run - -The lat/lon range is used to pick the region of the planet for generating statistics, for example your home state. To - -```shell -LAT_RANGE_MIN= \ -LAT_RANGE_MAX= \ -LON_RANGE_MIN= \ -LON_RANGE_MAX= \ -CDDIS_USERNAME= CDDIS_PASSWORD= \ -MQTT_BROKER_HOST="" MQTT_BROKER_PORT=1883 MQTT_USERNAME="user" MQTT_PASSWORD="" \ -python3 main.py -``` - -An example systemd service file is provided. - -### Home Assistant MQTT Config - -```yaml -- state_topic: "space-weather/vtec" - name: "VTEC" - unit_of_measurement: "(10^16 el) / m^2" - state_class: measurement - unique_id: space_weather_vtec -``` - -## Data - -### VTEC - - - -Unit: `(10^16 el) / m^2` - -VTEC, or Vertical TEC, is a specific type of TEC measurement that is taken along a path extending -vertically from the Earth's surface to the edge of the atmosphere. So essentially, VTEC is a subset of TEC, with the -difference lying in the specific path along which the measurement is taken. - -Updated hourly. \ No newline at end of file +This project consists of an external MQTT server, a custom component, and custom dashboard cards. \ No newline at end of file diff --git a/custom-component/README.md b/custom-component/README.md new file mode 100644 index 0000000..5ebfedb --- /dev/null +++ b/custom-component/README.md @@ -0,0 +1,4 @@ +## Install + +1. Copy `space_weather` to `config/custom_components` +2. Restart Home Assistant \ No newline at end of file diff --git a/custom-component/space_weather/sensor.py b/custom-component/space_weather/sensor.py index ccbd506..d0f3344 100644 --- a/custom-component/space_weather/sensor.py +++ b/custom-component/space_weather/sensor.py @@ -15,9 +15,12 @@ SCAN_INTERVAL = timedelta(minutes=30) async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): session = async_get_clientsession(hass) async_add_entities([ - SpaceWeatherScaleSensor(session, CONF_URL, "R"), - SpaceWeatherScaleSensor(session, CONF_URL, "S"), - SpaceWeatherScaleSensor(session, CONF_URL, "G"), + SpaceWeatherScaleSensor(session, CONF_URL, "R", '0', ''), + SpaceWeatherScaleSensor(session, CONF_URL, "S", '0', ''), + SpaceWeatherScaleSensor(session, CONF_URL, "G", '0', ''), + SpaceWeatherScaleSensor(session, CONF_URL, "R", '-1', '_24hr'), + SpaceWeatherScaleSensor(session, CONF_URL, "S", '-1', '_24hr'), + SpaceWeatherScaleSensor(session, CONF_URL, "G", '-1', '_24hr'), SpaceWeatherPredictionSensor(session, CONF_URL, "R", "MinorProb", "pred_r_minor"), SpaceWeatherPredictionSensor(session, CONF_URL, "R", "MajorProb", "pred_r_major"), SpaceWeatherPredictionSensor(session, CONF_URL, "S", "Scale", "pred_s_scale"), @@ -28,13 +31,15 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= class SpaceWeatherScaleSensor(Entity): - def __init__(self, session, url, scale_key): + def __init__(self, session, url, scale_key, data_selector, trailing): self._session = session self._url = url self._scale_key = scale_key - self._name = f'Space Weather Scale {scale_key}' + self._name = f'Space Weather Scale {scale_key} {trailing}' self._state = None self._data = None + self._data_selector = data_selector + self._trailing = trailing @property def name(self): @@ -42,7 +47,7 @@ class SpaceWeatherScaleSensor(Entity): @property def unique_id(self): - return f"space_weather_scale_{self._scale_key.lower()}" + return f"space_weather_scale_{self._scale_key.lower()}{self._trailing.replace('_', '')}" @property def state(self): @@ -63,7 +68,7 @@ class SpaceWeatherScaleSensor(Entity): async with self._session.get(self._url) as response: if response.status == 200: data = await response.json() - self._data = data["-1"] + self._data = data[self._data_selector] self._state = f'{self._scale_key}{self._data[self._scale_key]["Scale"]}' else: _LOGGER.error(f"Error fetching data from {self._url}") @@ -178,7 +183,7 @@ class SpaceWeatherDateStampSensor(Entity): tomorrow_data = v assert len(tomorrow_data.keys()) is not None self._data = tomorrow_data - self._state = datetime.strptime(f'{self._data["DateStamp"]} {self._data["TimeStamp"]}', "%Y-%m-%d %H:%M:%S").strftime('%m-%d-%Y %H:%M') + self._state = datetime.strptime(f'{self._data["DateStamp"]}', "%Y-%m-%d").strftime('%m-%d-%Y') else: _LOGGER.error(f"Error fetching data from {self._url}") except aiohttp.ClientError as err: diff --git a/dashboard/README.md b/dashboard/README.md new file mode 100644 index 0000000..9f4bf2b --- /dev/null +++ b/dashboard/README.md @@ -0,0 +1,17 @@ +## Install +1. Copy files from `www` to `config/www` +2. Dashboard > Edit > 3 button menu > Manage resources +3. Enter these 3 resources: + ``` + /local/space-weather-24hr-max-card.js?v=1 + /local/space-weather-card.js?v=1 + /local/space-weather-pred-card.js?v=1 + ``` +## Use +To add these custom cards, create a card of the "Manual" type. + +``` +type: space-weather-card-current +type: space-weather-prediction-card-1day +type: space-weather-card-24hr-max +``` \ No newline at end of file diff --git a/dashboard/www/space-weather-24hr-max-card.js b/dashboard/www/space-weather-24hr-max-card.js new file mode 100644 index 0000000..c982e2d --- /dev/null +++ b/dashboard/www/space-weather-24hr-max-card.js @@ -0,0 +1,157 @@ +class SpaceWeather24hrMaxCard extends HTMLElement { + constructor() { + super(); + this.attachShadow({mode: 'open'}); + } + + setConfig(config) { + this._config = config; + } + + set hass(hass) { + this._hass = hass; + this.render(); + } + + render() { + if (!this.shadowRoot) return; + + this.shadowRoot.innerHTML = ` + + + + +
+
+
+
+ ${this._getStateValue('sensor.space_weather_scale_r_24hr')} +
+
+ ${this._getStateAttribute('sensor.space_weather_scale_r_24hr', 'text')} +
+
+
+
+ ${this._getStateValue('sensor.space_weather_scale_s_24hr')} +
+
+ ${this._getStateAttribute('sensor.space_weather_scale_s_24hr', 'text')} +
+
+
+
+ ${this._getStateValue('sensor.space_weather_scale_g_24hr')} +
+
+ ${this._getStateAttribute('sensor.space_weather_scale_g_24hr', 'text')} +
+
+
+
+
+ `; + this._attachClickListeners(); + } + + _getStateValue(entityId) { + const state = this._hass.states[entityId]; + return state ? state.state : ''; + } + + _getStateAttribute(entityId, attribute) { + const state = this._hass.states[entityId]; + return state ? state.attributes[attribute] || '' : ''; + } + + _getNumericState(entityId) { + const stateValue = this._getStateValue(entityId); + return stateValue.substring(1); + } + + _attachClickListeners() { + const scaleItems = this.shadowRoot.querySelectorAll('.scale-item'); + scaleItems.forEach(item => { + item.addEventListener('click', () => { + const entityId = item.dataset.entityId; + this._handleClick(entityId); + }); + }); + } + + _handleClick(entityId) { + const event = new Event('hass-more-info', {composed: true}); + event.detail = {entityId}; + this.dispatchEvent(event); + } + + getCardSize() { + return 3; + } +} + +customElements.define('space-weather-card-24hr-max', SpaceWeather24hrMaxCard); diff --git a/dashboard/www/space-weather-card.js b/dashboard/www/space-weather-card.js index 00b083a..4edc3a1 100644 --- a/dashboard/www/space-weather-card.js +++ b/dashboard/www/space-weather-card.js @@ -157,4 +157,4 @@ class SpaceWeatherCard extends HTMLElement { } } -customElements.define('space-weather-card', SpaceWeatherCard); +customElements.define('space-weather-card-current', SpaceWeatherCard); diff --git a/dashboard/www/space-weather-pred-card.js b/dashboard/www/space-weather-pred-card.js index 333c946..0f0e241 100644 --- a/dashboard/www/space-weather-pred-card.js +++ b/dashboard/www/space-weather-pred-card.js @@ -20,15 +20,17 @@ class SpaceWeatherPredictionCard extends HTMLElement {