diff --git a/api/ecobee_thermostat.php b/api/ecobee_thermostat.php
index b2c7d55..6c786f4 100644
--- a/api/ecobee_thermostat.php
+++ b/api/ecobee_thermostat.php
@@ -211,6 +211,7 @@ class ecobee_thermostat extends cora\crud {
$attributes['property'] = $this->get_property($thermostat, $ecobee_thermostat);
$attributes['filters'] = $this->get_filters($thermostat, $ecobee_thermostat);
$attributes['json_alerts'] = $this->get_alerts($thermostat, $ecobee_thermostat);
+ $attributes['weather'] = $this->get_weather($thermostat, $ecobee_thermostat);
$detected_system_type = $this->get_detected_system_type($thermostat, $ecobee_thermostat);
if($thermostat['system_type'] === null) {
@@ -719,4 +720,145 @@ class ecobee_thermostat extends cora\crud {
return $detected_system_type;
}
+ /**
+ * Get the current weather status.
+ *
+ * @param array $thermostat
+ * @param array $ecobee_thermostat
+ *
+ * @return array
+ */
+ private function get_weather($thermostat, $ecobee_thermostat) {
+ $weather = [
+ 'station' => null,
+ 'dew_point' => null,
+ 'barometric_pressure' => null,
+ 'humidity_relative' => null,
+ 'temperature_high' => null,
+ 'temperature_low' => null,
+ 'temperature' => null,
+ 'wind_bearing' => null,
+ 'wind_speed' => null,
+ 'condition' => null
+ ];
+
+ if(isset($ecobee_thermostat['json_weather']['weatherStation']) === true) {
+ $weather['station'] = $ecobee_thermostat['json_weather']['weatherStation'];
+ }
+
+ if(
+ isset($ecobee_thermostat['json_weather']['forecasts']) === true &&
+ isset($ecobee_thermostat['json_weather']['forecasts'][0]) === true
+ ) {
+ $ecobee_weather = $ecobee_thermostat['json_weather']['forecasts'][0];
+
+ if(isset($ecobee_weather['dewpoint']) === true) {
+ $weather['dew_point'] = ($ecobee_weather['dewpoint'] / 10);
+ }
+
+ // Returned in MB (divide by 33.864 to get inHg)
+ if(isset($ecobee_weather['pressure']) === true) {
+ $weather['barometric_pressure'] = $ecobee_weather['pressure'];
+ }
+
+ if(isset($ecobee_weather['relativeHumidity']) === true) {
+ $weather['humidity_relative'] = $ecobee_weather['relativeHumidity'];
+ }
+
+ if(isset($ecobee_weather['tempHigh']) === true) {
+ $weather['temperature_high'] = ($ecobee_weather['tempHigh'] / 10);
+ }
+
+ if(isset($ecobee_weather['tempLow']) === true) {
+ $weather['temperature_low'] = ($ecobee_weather['tempLow'] / 10);
+ }
+
+ if(isset($ecobee_weather['temperature']) === true) {
+ $weather['temperature'] = ($ecobee_weather['temperature'] / 10);
+ }
+
+ if(isset($ecobee_weather['windBearing']) === true) {
+ $weather['wind_bearing'] = $ecobee_weather['windBearing'];
+ }
+
+ // mph
+ if(isset($ecobee_weather['windSpeed']) === true) {
+ $weather['wind_speed'] = $ecobee_weather['windSpeed'];
+ }
+
+ if(isset($ecobee_weather['weatherSymbol']) === true) {
+ switch($ecobee_weather['weatherSymbol']) {
+ case 0:
+ $weather['condition'] = 'sunny';
+ break;
+ case 1:
+ $weather['condition'] = 'few_clouds';
+ break;
+ case 2:
+ $weather['condition'] = 'partly_cloudy';
+ break;
+ case 3:
+ $weather['condition'] = 'mostly_cloudy';
+ break;
+ case 4:
+ $weather['condition'] = 'overcast';
+ break;
+ case 5:
+ $weather['condition'] = 'drizzle';
+ break;
+ case 6:
+ $weather['condition'] = 'rain';
+ break;
+ case 7:
+ $weather['condition'] = 'freezing_rain';
+ break;
+ case 8:
+ $weather['condition'] = 'showers';
+ break;
+ case 9:
+ $weather['condition'] = 'hail';
+ break;
+ case 10:
+ $weather['condition'] = 'snow';
+ break;
+ case 11:
+ $weather['condition'] = 'flurries';
+ break;
+ case 12:
+ $weather['condition'] = 'freezing_snow';
+ break;
+ case 13:
+ $weather['condition'] = 'blizzard';
+ break;
+ case 14:
+ $weather['condition'] = 'pellets';
+ break;
+ case 15:
+ $weather['condition'] = 'thunderstorm';
+ break;
+ case 16:
+ $weather['condition'] = 'windy';
+ break;
+ case 17:
+ $weather['condition'] = 'tornado';
+ break;
+ case 18:
+ $weather['condition'] = 'fog';
+ break;
+ case 19:
+ $weather['condition'] = 'haze';
+ break;
+ case 20:
+ $weather['condition'] = 'smoke';
+ break;
+ case 21:
+ $weather['condition'] = 'dust';
+ break;
+ }
+ }
+ }
+
+ return $weather;
+ }
+
}
diff --git a/api/thermostat.php b/api/thermostat.php
index 4486246..b631aab 100644
--- a/api/thermostat.php
+++ b/api/thermostat.php
@@ -33,6 +33,9 @@ class thermostat extends cora\crud {
],
'system_type' => [
'type' => 'json'
+ ],
+ 'weather' => [
+ 'type' => 'json'
]
];
diff --git a/css/dashboard.css b/css/dashboard.css
index 2b50238..5311b45 100644
--- a/css/dashboard.css
+++ b/css/dashboard.css
@@ -380,6 +380,19 @@ a.inverted:active {
.icon.zigbee:before { content: "\FD1D"; }
.icon.basket_fill:before { content: "\F077"; }
.icon.basket_unfill:before { content: "\F078"; }
+.icon.weather_sunny:before { content: "\F599"; }
+.icon.weather_partly_cloudy:before { content: "\F595"; }
+.icon.weather_cloudy:before { content: "\F590"; }
+.icon.weather_pouring:before { content: "\F596"; }
+.icon.weather_hail:before { content: "\F592"; }
+.icon.weather_snowy:before { content: "\F598"; }
+.icon.weather_snowy_heavy:before { content: "\FF53"; }
+.icon.weather_lightning_rainy:before { content: "\F67D"; }
+.icon.weather_windy:before { content: "\F59D"; }
+.icon.weather_fog:before { content: "\F591"; }
+.icon.weather_hazy:before { content: "\FF4D"; }
+.icon.weather_tornado:before { content: "\FF55"; }
+.icon.cloud_question:before { content: "\FA38"; }
.icon.f16:before { font-size: 16px; }
.icon.f24:before { font-size: 24px; }
diff --git a/font/material_icon/material_icon.eot b/font/material_icon/material_icon.eot
index 601bd68..71224e5 100644
Binary files a/font/material_icon/material_icon.eot and b/font/material_icon/material_icon.eot differ
diff --git a/font/material_icon/material_icon.svg b/font/material_icon/material_icon.svg
deleted file mode 100644
index 9807d07..0000000
--- a/font/material_icon/material_icon.svg
+++ /dev/null
@@ -1,10491 +0,0 @@
-
-
-
diff --git a/font/material_icon/material_icon.ttf b/font/material_icon/material_icon.ttf
index 31a801b..569f59e 100644
Binary files a/font/material_icon/material_icon.ttf and b/font/material_icon/material_icon.ttf differ
diff --git a/font/material_icon/material_icon.woff b/font/material_icon/material_icon.woff
index 8615de3..71825c0 100644
Binary files a/font/material_icon/material_icon.woff and b/font/material_icon/material_icon.woff differ
diff --git a/font/material_icon/material_icon.woff2 b/font/material_icon/material_icon.woff2
index 2371b5e..582536a 100644
Binary files a/font/material_icon/material_icon.woff2 and b/font/material_icon/material_icon.woff2 differ
diff --git a/js/component/card/system.js b/js/component/card/system.js
index 0bd2cfc..fd69ba1 100644
--- a/js/component/card/system.js
+++ b/js/component/card/system.js
@@ -15,6 +15,7 @@ beestat.extend(beestat.component.card.system, beestat.component.card);
beestat.component.card.system.prototype.decorate_contents_ = function(parent) {
this.decorate_circle_(parent);
+ this.decorate_weather_(parent);
this.decorate_equipment_(parent);
this.decorate_climate_(parent);
};
@@ -78,6 +79,72 @@ beestat.component.card.system.prototype.decorate_circle_ = function(parent) {
);
};
+beestat.component.card.system.prototype.decorate_weather_ = function(parent) {
+ var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
+
+ var temperature = beestat.temperature(thermostat.weather.temperature);
+ var temperature_whole = Math.floor(temperature);
+
+ var circle = $.createElement('div')
+ .style({
+ 'padding': (beestat.style.size.gutter / 2),
+ 'border-radius': '50%',
+ 'background': beestat.style.color.bluegray.light,
+ 'height': '66px',
+ 'width': '66px',
+ 'text-align': 'center',
+ 'text-shadow': '1px 1px 1px rgba(0, 0, 0, 0.2)',
+ 'position': 'absolute',
+ 'top': '90px',
+ 'left': '50%',
+ 'margin-left': '40px',
+ 'cursor': 'pointer',
+ 'transition': 'background 200ms ease'
+ });
+ parent.appendChild(circle);
+
+ circle
+ .addEventListener('mouseover', function() {
+ circle.style('background', beestat.style.color.gray.dark);
+ })
+ .addEventListener('mouseout', function() {
+ circle.style('background', beestat.style.color.bluegray.light);
+ })
+ .addEventListener('click', function() {
+ (new beestat.component.modal.weather()).render();
+ });
+
+ var temperature_container = $.createElement('div');
+ circle.appendChild(temperature_container);
+
+ var temperature_whole_container = $.createElement('span')
+ .style({
+ 'font-size': '22px',
+ 'font-weight': beestat.style.font_weight.light
+ })
+ .innerHTML(temperature_whole);
+ temperature_container.appendChild(temperature_whole_container);
+
+ var humidity_container = $.createElement('div')
+ .style({
+ 'display': 'inline-flex',
+ 'align-items': 'center'
+ });
+ circle.appendChild(humidity_container);
+
+ (new beestat.component.icon('water_percent')
+ .set_size(16)
+ ).render(humidity_container);
+
+ humidity_container.appendChild(
+ $.createElement('span')
+ .innerHTML(thermostat.weather.humidity_relative + '%')
+ .style({
+ 'font-size': '10px'
+ })
+ );
+};
+
/**
* Decorate the running equipment list on the bottom left.
*
diff --git a/js/component/modal/weather.js b/js/component/modal/weather.js
new file mode 100644
index 0000000..2592f8b
--- /dev/null
+++ b/js/component/modal/weather.js
@@ -0,0 +1,245 @@
+/**
+ * Current weather.
+ */
+beestat.component.modal.weather = function() {
+ var self = this;
+
+ beestat.dispatcher.addEventListener(
+ 'cache.thermostat',
+ function() {
+ self.rerender();
+ }
+ );
+
+ beestat.component.modal.apply(this, arguments);
+};
+beestat.extend(beestat.component.modal.weather, beestat.component.modal);
+
+beestat.component.modal.weather.prototype.decorate_contents_ = function(parent) {
+ var thermostat = beestat.cache.thermostat[beestat.setting('thermostat_id')];
+
+ var icon;
+ var icon_color;
+ switch (thermostat.weather.condition) {
+ case 'sunny':
+ icon = 'weather_sunny';
+ icon_color = beestat.style.color.yellow.base;
+ break;
+ case 'few_clouds':
+ case 'partly_cloudy':
+ icon = 'weather_partly_cloudy';
+ icon_color = beestat.style.color.gray.base;
+ break;
+ case 'mostly_cloudy':
+ case 'overcast':
+ icon = 'weather_cloudy';
+ icon_color = beestat.style.color.gray.base;
+ break;
+ case 'drizzle':
+ case 'rain':
+ case 'showers':
+ icon = 'weather_pouring';
+ icon_color = beestat.style.color.blue.light;
+ break;
+ case 'freezing_rain':
+ case 'hail':
+ case 'pellets':
+ icon_color = beestat.style.color.lightblue.base;
+ icon = 'weather_hail';
+ break;
+ case 'snow':
+ case 'flurries':
+ case 'freezing_snow':
+ icon_color = beestat.style.color.lightblue.light;
+ icon = 'weather_snowy';
+ break;
+ case 'blizzard':
+ icon = 'weather_snowy_heavy';
+ icon_color = beestat.style.color.lightblue.light;
+ break;
+ case 'thunderstorm':
+ icon = 'weather_lightning_rainy';
+ icon_color = beestat.style.color.red.base;
+ break;
+ case 'windy':
+ icon = 'weather_windy';
+ icon_color = beestat.style.color.gray.base;
+ break;
+ case 'tornado':
+ icon = 'weather_tornado';
+ icon_color = beestat.style.color.gray.base;
+ break;
+ case 'fog':
+ icon = 'weather_fog';
+ icon_color = beestat.style.color.gray.base;
+ break;
+ case 'haze':
+ case 'smoke':
+ case 'dust':
+ icon = 'weather_hazy';
+ icon_color = beestat.style.color.gray.base;
+ break;
+ default:
+ icon = 'cloud_question';
+ icon_color = beestat.style.color.gray.base;
+ break;
+ }
+
+ var condition = thermostat.weather.condition.replace('_', ' ');
+ condition = condition.charAt(0).toUpperCase() + condition.slice(1);
+
+ var tr;
+ var td;
+
+ var table = $.createElement('table');
+
+ tr = $.createElement('tr');
+ table.appendChild(tr);
+
+ td = $.createElement('td')
+ .setAttribute('rowspan', '2')
+ .style({
+ 'padding-right': beestat.style.size.gutter
+ });
+ (new beestat.component.icon(icon))
+ .set_size(64)
+ .set_color(icon_color)
+ .render(td);
+ tr.appendChild(td);
+
+ td = $.createElement('td');
+ td.appendChild(
+ $.createElement('span')
+ .innerText(
+ beestat.temperature({
+ 'round': 0,
+ 'units': true,
+ 'temperature': thermostat.weather.temperature
+ })
+ )
+ .style({
+ 'font-size': '24px'
+ })
+ );
+ td.appendChild(
+ $.createElement('span')
+ .innerText(condition)
+ .style({
+ 'font-size': '18px',
+ 'padding-left': (beestat.style.size.gutter / 2)
+ })
+ );
+ tr.appendChild(td);
+
+ tr = $.createElement('tr').style('color', beestat.style.color.gray.base);
+ table.appendChild(tr);
+
+ td = $.createElement('td');
+ // Low
+ td.appendChild($.createElement('span').innerText('Low: '));
+ td.appendChild(
+ $.createElement('span')
+ .innerText(
+ beestat.temperature({
+ 'round': 0,
+ 'units': false,
+ 'temperature': thermostat.weather.temperature_low
+ })
+ )
+ .style({
+ 'padding-right': (beestat.style.size.gutter / 2)
+ })
+ );
+ // High
+ td.appendChild($.createElement('span').innerText('High: '));
+ td.appendChild(
+ $.createElement('span')
+ .innerText(
+ beestat.temperature({
+ 'round': 0,
+ 'units': false,
+ 'temperature': thermostat.weather.temperature_high
+ })
+ )
+ );
+
+ tr.appendChild(td);
+
+ parent.appendChild(table);
+
+ var container = $.createElement('div')
+ .style({
+ 'display': 'grid',
+ 'grid-template-columns': 'repeat(auto-fill, minmax(120px, 1fr))',
+ 'margin': '0 0 16px -16px'
+ });
+ parent.appendChild(container);
+
+ var bearings = [
+ 'N',
+ 'NNE',
+ 'NE',
+ 'ENE',
+ 'E',
+ 'ESE',
+ 'SE',
+ 'SSE',
+ 'S',
+ 'SSW',
+ 'SW',
+ 'WSW',
+ 'W',
+ 'WNW',
+ 'NW',
+ 'NNW'
+ ];
+
+ var fields = [
+ {
+ 'name': 'Humidity',
+ 'value': thermostat.weather.humidity_relative + '%'
+ },
+ {
+ 'name': 'Dew Point',
+ 'value': beestat.temperature({
+ 'round': 0,
+ 'units': true,
+ 'temperature': thermostat.weather.dew_point
+ })
+ },
+ {
+ 'name': 'Wind',
+ 'value': thermostat.weather.wind_speed === 0
+ ? '0mph'
+ : thermostat.weather.wind_speed + 'mph ' + bearings[Math.floor(((thermostat.weather.wind_bearing / 22.5) + 0.5) % 16)]
+ },
+ {
+ 'name': 'Pressure',
+ 'value': thermostat.weather.barometric_pressure + 'mb'
+ },
+ {
+ 'name': 'Station',
+ 'value': thermostat.weather.station
+ }
+ ];
+
+ fields.forEach(function(field) {
+ var div = $.createElement('div')
+ .style({
+ 'padding': '16px 0 0 16px'
+ });
+ container.appendChild(div);
+
+ div.appendChild($.createElement('div')
+ .style({
+ 'font-weight': beestat.style.font_weight.bold,
+ 'margin-bottom': (beestat.style.size.gutter / 4)
+ })
+ .innerHTML(field.name));
+ div.appendChild($.createElement('div').innerHTML(field.value));
+ });
+};
+
+beestat.component.modal.weather.prototype.get_title_ = function() {
+ return 'Weather';
+};
diff --git a/js/js.php b/js/js.php
index 966393c..3c69041 100644
--- a/js/js.php
+++ b/js/js.php
@@ -83,6 +83,7 @@ if($setting->get('environment') === 'dev' || $setting->get('environment') === 'd
echo '' . PHP_EOL;
echo '' . PHP_EOL;
echo '' . PHP_EOL;
+ echo '' . PHP_EOL;
echo '' . PHP_EOL;
echo '' . PHP_EOL;
echo '' . PHP_EOL;