add 24 hr max scales, improve readmes, reorganize pred card layout
This commit is contained in:
parent
85636814ed
commit
57fbbe4627
59
README.md
59
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 <https://urs.earthdata.nasa.gov>
|
||||
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=<lower range for lat bounding box> \
|
||||
LAT_RANGE_MAX=<upper range for lat bounding box> \
|
||||
LON_RANGE_MIN=<lower range for lon bounding box> \
|
||||
LON_RANGE_MAX=<upper range for lon bounding box> \
|
||||
CDDIS_USERNAME=<username> CDDIS_PASSWORD=<password> \
|
||||
MQTT_BROKER_HOST="<Home Assistant IP>" MQTT_BROKER_PORT=1883 MQTT_USERNAME="user" MQTT_PASSWORD="<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
|
||||
|
||||
<https://www.spaceweather.gov/products/us-total-electron-content>
|
||||
|
||||
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.
|
||||
This project consists of an external MQTT server, a custom component, and custom dashboard cards.
|
|
@ -0,0 +1,4 @@
|
|||
## Install
|
||||
|
||||
1. Copy `space_weather` to `config/custom_components`
|
||||
2. Restart Home Assistant
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
```
|
|
@ -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 = `
|
||||
<style>
|
||||
.scale-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.scale-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scale-label {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.scale-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.scale-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.noaa_scale_bg_5 {
|
||||
background-color: #C80000;
|
||||
}
|
||||
.noaa_scale_bg_4 {
|
||||
background-color: #FF0000;
|
||||
}
|
||||
.noaa_scale_bg_3 {
|
||||
background-color: #FF9600;
|
||||
}
|
||||
.noaa_scale_bg_2 {
|
||||
background-color: #FFC800;
|
||||
}
|
||||
.noaa_scale_bg_1 {
|
||||
background-color: #F6EB14;
|
||||
}
|
||||
.noaa_scale_bg_0 {
|
||||
background-color: #92D050;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scale-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ha-card>
|
||||
<div class="card-header">
|
||||
<a href="https://www.spaceweather.gov/noaa-scales-explanation" target="_blank">Space Weather 24-Hour Maximums</a>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="scale-container">
|
||||
<div class="scale-item" data-entity-id="sensor.space_weather_scale_r_24hr">
|
||||
<div class="scale-value noaa_scale_bg_${this._getNumericState('sensor.space_weather_scale_r_24hr')}">
|
||||
${this._getStateValue('sensor.space_weather_scale_r_24hr')}
|
||||
</div>
|
||||
<div class="scale-text">
|
||||
${this._getStateAttribute('sensor.space_weather_scale_r_24hr', 'text')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="scale-item" data-entity-id="sensor.space_weather_scale_s_24hr">
|
||||
<div class="scale-value noaa_scale_bg_${this._getNumericState('sensor.space_weather_scale_s_24hr')}">
|
||||
${this._getStateValue('sensor.space_weather_scale_s_24hr')}
|
||||
</div>
|
||||
<div class="scale-text">
|
||||
${this._getStateAttribute('sensor.space_weather_scale_s_24hr', 'text')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="scale-item" data-entity-id="sensor.space_weather_scale_g_24hr">
|
||||
<div class="scale-value noaa_scale_bg_${this._getNumericState('sensor.space_weather_scale_g_24hr')}">
|
||||
${this._getStateValue('sensor.space_weather_scale_g_24hr')}
|
||||
</div>
|
||||
<div class="scale-text">
|
||||
${this._getStateAttribute('sensor.space_weather_scale_g_24hr', 'text')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
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);
|
|
@ -157,4 +157,4 @@ class SpaceWeatherCard extends HTMLElement {
|
|||
}
|
||||
}
|
||||
|
||||
customElements.define('space-weather-card', SpaceWeatherCard);
|
||||
customElements.define('space-weather-card-current', SpaceWeatherCard);
|
||||
|
|
|
@ -20,15 +20,17 @@ class SpaceWeatherPredictionCard extends HTMLElement {
|
|||
<style>
|
||||
/* TODO: unify this with the other card */
|
||||
|
||||
.prediction-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.prediction-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
.prediction-item {
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
/*margin-bottom: 16px;*/
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -96,7 +98,7 @@ class SpaceWeatherPredictionCard extends HTMLElement {
|
|||
<ha-card>
|
||||
<div class="card-header">Space Weather Predictions</div>
|
||||
<div class="card-subheader">
|
||||
${this._getStateValue('sensor.space_weather_prediction_date_stamp')}
|
||||
For ${this._getStateValue('sensor.space_weather_prediction_date_stamp')}
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="prediction-container">
|
||||
|
@ -179,4 +181,4 @@ class SpaceWeatherPredictionCard extends HTMLElement {
|
|||
}
|
||||
}
|
||||
|
||||
customElements.define('space-weather-prediction-card', SpaceWeatherPredictionCard);
|
||||
customElements.define('space-weather-prediction-card-1day', SpaceWeatherPredictionCard);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
This is an MQTT sensor to send NOAA space weather data to Home Assistant.
|
||||
|
||||
## Install
|
||||
|
||||
1. Create an account at <https://urs.earthdata.nasa.gov>
|
||||
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=<lower range for lat bounding box> \
|
||||
LAT_RANGE_MAX=<upper range for lat bounding box> \
|
||||
LON_RANGE_MIN=<lower range for lon bounding box> \
|
||||
LON_RANGE_MAX=<upper range for lon bounding box> \
|
||||
CDDIS_USERNAME=<username> CDDIS_PASSWORD=<password> \
|
||||
MQTT_BROKER_HOST="<Home Assistant IP>" MQTT_BROKER_PORT=1883 MQTT_USERNAME="user" MQTT_PASSWORD="<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
|
||||
|
||||
<https://www.spaceweather.gov/products/us-total-electron-content>
|
||||
|
||||
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.
|
|
@ -6,7 +6,7 @@ After=network.target
|
|||
Type=simple
|
||||
User=homeassistant
|
||||
EnvironmentFile=/etc/secrets/space-weather
|
||||
ExecStart=/srv/space-weather/ha-noaa-space-weather-sensor/venv/bin/python /srv/space-weather/ha-noaa-space-weather-sensor/feeder-mqtt/main.py
|
||||
ExecStart=/srv/space-weather/ha-noaa-space-weather/venv/bin/python /srv/space-weather/ha-noaa-space-weather-sensor/feeder-mqtt/main.py
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
Loading…
Reference in New Issue