- added 'weather' data source and custom card
- fixes #89 - fixes #88 - fixes #82
@ -47,6 +47,8 @@ docker create \
|
|||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
rmountjoy/dashmachine:latest
|
rmountjoy/dashmachine:latest
|
||||||
```
|
```
|
||||||
|
### Synology
|
||||||
|
Check out this awesome guide: https://nashosted.com/manage-your-self-hosted-applications-using-dashmachine/
|
||||||
### Python
|
### Python
|
||||||
Instructions are for linux.
|
Instructions are for linux.
|
||||||
```
|
```
|
||||||
|
@ -191,14 +191,11 @@ def read_config():
|
|||||||
db.session.merge(tag_db)
|
db.session.merge(tag_db)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
else:
|
else:
|
||||||
if Tags.query.first():
|
app.tags = "Untagged"
|
||||||
app.tags = "Untagged"
|
if not Tags.query.filter_by(name="Untagged").first():
|
||||||
if not Tags.query.filter_by(name="Untagged").first():
|
tag_db = Tags(name="Untagged")
|
||||||
tag_db = Tags(name="Untagged")
|
db.session.add(tag_db)
|
||||||
db.session.add(tag_db)
|
db.session.commit()
|
||||||
db.session.commit()
|
|
||||||
else:
|
|
||||||
app.tags = None
|
|
||||||
|
|
||||||
db.session.add(app)
|
db.session.add(app)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -19,8 +19,8 @@ value_template = {{ value_template }}
|
|||||||
| platform | Yes | Name of the platform. | transmission |
|
| platform | Yes | Name of the platform. | transmission |
|
||||||
| host | Yes | Host of Transmission Web UI | host |
|
| host | Yes | Host of Transmission Web UI | host |
|
||||||
| port | Yes | Port of Transmission Web UI | port |
|
| port | Yes | Port of Transmission Web UI | port |
|
||||||
| user | No | Username for Transmission Web UI | username |
|
| user | Yes | Username for Transmission Web UI | username |
|
||||||
| password | No | Password for Transmission Web UI | password |
|
| password | Yes | Password for Transmission Web UI | password |
|
||||||
| value_template | Yes | Jinja template for how the returned data from API is displayed. | jinja template |
|
| value_template | Yes | Jinja template for how the returned data from API is displayed. | jinja template |
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
130
dashmachine/platform/weather.py
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
"""
|
||||||
|
|
||||||
|
##### Weather
|
||||||
|
Weather is a great example of how you can populate a custom card on the dash. This plugin creates a custom card with weather data from [metaweather.com](https://www.metaweather.com)
|
||||||
|
```ini
|
||||||
|
[variable_name]
|
||||||
|
platform = weather
|
||||||
|
woeid = 2514815
|
||||||
|
temp_unit = c
|
||||||
|
wind_speed_unit = kph
|
||||||
|
air_pressure_unit = mbar
|
||||||
|
visibility_unit = km
|
||||||
|
```
|
||||||
|
> **Returns:** HTML for custom card
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|-----------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------|-------------------|
|
||||||
|
| [variable_name] | Yes | Name for the data source. | [variable_name] |
|
||||||
|
| platform | Yes | Name of the platform. | weather |
|
||||||
|
| woeid | Yes | woeid of location to use. Go here to get (replace lat and long): https://www.metaweather.com/api/location/search/?lattlong=50.068,-5.316 | url |
|
||||||
|
| temp_unit | No | The unit to be used for temperature | c,f |
|
||||||
|
| wind_speed_unit | No | The unit to be used for wind speed | kph,mph |
|
||||||
|
| air_pressure_unit | No | The unit to be used for air pressure | mbar, inHg |
|
||||||
|
| visibility_unit | No | The unit to be used for visibility | km,mi |
|
||||||
|
|
||||||
|
> **Working example:**
|
||||||
|
>```ini
|
||||||
|
>[variable_name]
|
||||||
|
>platform = weather
|
||||||
|
>woeid = 2514815
|
||||||
|
>
|
||||||
|
>[custom_card_name]
|
||||||
|
>type = custom
|
||||||
|
>data_sources = variable_name
|
||||||
|
>```
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from flask import render_template_string
|
||||||
|
|
||||||
|
|
||||||
|
class Platform:
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# parse the user's options from the config entries
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
self.__dict__[key] = value
|
||||||
|
|
||||||
|
# set defaults for omitted options
|
||||||
|
if not hasattr(self, "woeid"):
|
||||||
|
self.woeid = 2514815
|
||||||
|
if not hasattr(self, "temp_unit"):
|
||||||
|
self.temp_unit = "c"
|
||||||
|
if not hasattr(self, "wind_speed_unit"):
|
||||||
|
self.wind_speed_unit = "kph"
|
||||||
|
if not hasattr(self, "air_pressure_unit"):
|
||||||
|
self.air_pressure_unit = "x"
|
||||||
|
if not hasattr(self, "visibility_unit"):
|
||||||
|
self.visibility_unit = "km"
|
||||||
|
|
||||||
|
self.html_template = """
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s6">
|
||||||
|
<span class="mt-0 mb-0 theme-primary-text font-weight-700" style="font-size: 36px">{{ value.consolidated_weather[0].the_temp|round(1, 'floor') }}°</h3>
|
||||||
|
</div>
|
||||||
|
<div class="col s6 right-align">
|
||||||
|
<img height="48px" src="https://www.metaweather.com/static/img/weather/{{ value.consolidated_weather[0].weather_state_abbr }}.svg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<h6 class="font-weight-900 center theme-muted-text">{{ value.parent.title }}</h6>
|
||||||
|
</div>
|
||||||
|
<div class="row center-align">
|
||||||
|
<i class="material-icons-outlined">keyboard_arrow_down</i>
|
||||||
|
</div>
|
||||||
|
<div class="row center-align">
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="collection theme-muted-text">
|
||||||
|
<div class="collection-item"><span class="font-weight-900">Currently: </span>{{ value.consolidated_weather[0].weather_state_name }}</div>
|
||||||
|
<div class="collection-item"><span class="font-weight-900">Min: </span>{{ value.consolidated_weather[0].min_temp|round(1, 'floor') }}° <span class="font-weight-900">Max: </span>{{ value.consolidated_weather[0].max_temp|round(1, 'floor') }}°</div>
|
||||||
|
<div class="collection-item"><span class="font-weight-900">Wind: </span>{{ value.consolidated_weather[0].wind_direction_compass }} at {{ value.consolidated_weather[0].wind_speed|round(1, 'floor') }} {{ wind_speed_unit }}</div>
|
||||||
|
<div class="collection-item"><span class="font-weight-900">Humidity: </span>{{ value.consolidated_weather[0].humidity }}%</div>
|
||||||
|
<div class="collection-item"><span class="font-weight-900">Air Pressure: </span>{{ value.consolidated_weather[0].air_pressure|round(1, 'floor') }}</div>
|
||||||
|
<div class="collection-item"><span class="font-weight-900">Visibility: </span>{{ value.consolidated_weather[0].visibility|round(1, 'floor') }}</div>
|
||||||
|
<div class="collection-item"><span class="font-weight-900">Predictability: </span>{{ value.consolidated_weather[0].predictability }}%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.error_template = """
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12">
|
||||||
|
<span class="theme-failure-text font-weight-900">Check your config. This error was returned: {{ error }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def process(self):
|
||||||
|
try:
|
||||||
|
value = requests.get(
|
||||||
|
f"https://www.metaweather.com/api/location/{self.woeid}"
|
||||||
|
).json()
|
||||||
|
except Exception as error:
|
||||||
|
return render_template_string(self.error_template, error=error)
|
||||||
|
|
||||||
|
if self.temp_unit.lower() == "f":
|
||||||
|
value["consolidated_weather"][0]["the_temp"] = (
|
||||||
|
value["consolidated_weather"][0]["the_temp"] * 1.8
|
||||||
|
) + 32
|
||||||
|
value["consolidated_weather"][0]["min_temp"] = (
|
||||||
|
value["consolidated_weather"][0]["min_temp"] * 1.8
|
||||||
|
) + 32
|
||||||
|
value["consolidated_weather"][0]["max_temp"] = (
|
||||||
|
value["consolidated_weather"][0]["max_temp"] * 1.8
|
||||||
|
) + 32
|
||||||
|
|
||||||
|
if self.wind_speed_unit.lower() == "mph":
|
||||||
|
value["consolidated_weather"][0]["wind_speed"] = (
|
||||||
|
value["consolidated_weather"][0]["wind_speed"] * 1.609
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.air_pressure_unit.lower() == "inhg":
|
||||||
|
value["consolidated_weather"][0]["air_pressure"] = (
|
||||||
|
value["consolidated_weather"][0]["air_pressure"] / 33.864
|
||||||
|
)
|
||||||
|
|
||||||
|
return render_template_string(
|
||||||
|
self.html_template, value=value, wind_speed_unit=self.wind_speed_unit
|
||||||
|
)
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.6 KiB |
@ -18,4 +18,4 @@
|
|||||||
|
|
||||||
{% block page_lvl_js %}
|
{% block page_lvl_js %}
|
||||||
|
|
||||||
{% endblock page_lvl_js %}
|
{% endblock page_lvl_js %}
|
@ -28,10 +28,12 @@
|
|||||||
<i class="material-icons prefix card-search-icon">search</i>
|
<i class="material-icons prefix card-search-icon">search</i>
|
||||||
<input type="text" id="apps-filter" class="card-filter theme-surface-transparent" placeholder="Search apps" autofocus>
|
<input type="text" id="apps-filter" class="card-filter theme-surface-transparent" placeholder="Search apps" autofocus>
|
||||||
|
|
||||||
<i id="toggle-tag-expand-all-btn" class="material-icons right filter-action pointer">unfold_less</i>
|
{% if tags_form.tags.choices|count > 2 %}
|
||||||
|
<i id="toggle-tag-expand-all-btn" class="material-icons right filter-action pointer">unfold_less</i>
|
||||||
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% if tags_form.tags.choices|count > 1 %}
|
{% if tags_form.tags.choices|count > 2 %}
|
||||||
<div class="input-field col s6 m4 l2 offset-s3 offset-m4 tags-select-col theme-surface-transparent">
|
<div class="input-field col s6 m4 l2 offset-s3 offset-m4 tags-select-col theme-surface-transparent">
|
||||||
{{ tags_form.tags(id='tags-select') }}
|
{{ tags_form.tags(id='tags-select') }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
version = "v0.5"
|
version = "v0.5"
|
||||||
revision_number = "3"
|
revision_number = "4"
|
||||||
|