Add Celsius/Fahrenheit temperature unit toggle (v2.2.0)

- New `temperature_unit` config option ('C' or 'F', default 'F')
- Temperature thresholds, graph ranges, and status labels adapt to unit
- Toggle available in both modern and fallback visual editors
This commit is contained in:
KadenThomp36 2026-02-11 11:29:35 -05:00
parent ef2922a1f6
commit 1667470bc7
2 changed files with 46 additions and 12 deletions

View file

@ -55,6 +55,7 @@ temperature_entity: sensor.air_quality_temperature
air_quality_entity: sensor.air_quality_index air_quality_entity: sensor.air_quality_index
recommendation_entity: sensor.air_quality_recommendation recommendation_entity: sensor.air_quality_recommendation
hours_to_show: 24 hours_to_show: 24
temperature_unit: C
``` ```
### Configuration Options ### Configuration Options
@ -69,6 +70,7 @@ hours_to_show: 24
| `air_quality_entity` | string | No | - | Overall air quality index entity | | `air_quality_entity` | string | No | - | Overall air quality index entity |
| `recommendation_entity` | string | No | - | Recommendation template sensor | | `recommendation_entity` | string | No | - | Recommendation template sensor |
| `hours_to_show` | number | No | 24 | Hours of history to display (1-168) | | `hours_to_show` | number | No | 24 | Hours of history to display (1-168) |
| `temperature_unit` | string | No | "F" | Temperature unit: "F" (Fahrenheit) or "C" (Celsius) |
## Recommendation Sensor ## Recommendation Sensor

View file

@ -6,7 +6,7 @@
* https://github.com/KadenThomp36/air-quality-card * https://github.com/KadenThomp36/air-quality-card
*/ */
const CARD_VERSION = '2.1.0'; const CARD_VERSION = '2.2.0';
class AirQualityCard extends HTMLElement { class AirQualityCard extends HTMLElement {
// Visual editor using getConfigForm (preferred modern approach) // Visual editor using getConfigForm (preferred modern approach)
@ -35,6 +35,7 @@ class AirQualityCard extends HTMLElement {
{ name: 'air_quality_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'air_quality_entity', selector: { entity: { domain: 'sensor' } } },
{ name: 'recommendation_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'recommendation_entity', selector: { entity: { domain: 'sensor' } } },
{ name: 'hours_to_show', selector: { number: { min: 1, max: 168, mode: 'box', unit_of_measurement: 'hours' } } }, { name: 'hours_to_show', selector: { number: { min: 1, max: 168, mode: 'box', unit_of_measurement: 'hours' } } },
{ name: 'temperature_unit', selector: { select: { options: [{ value: 'F', label: 'Fahrenheit (°F)' }, { value: 'C', label: 'Celsius (°C)' }], mode: 'dropdown' } } },
] ]
} }
], ],
@ -47,7 +48,8 @@ class AirQualityCard extends HTMLElement {
temperature_entity: 'Temperature Sensor (optional)', temperature_entity: 'Temperature Sensor (optional)',
air_quality_entity: 'Air Quality Index (optional)', air_quality_entity: 'Air Quality Index (optional)',
recommendation_entity: 'Recommendation Sensor (optional)', recommendation_entity: 'Recommendation Sensor (optional)',
hours_to_show: 'Graph History' hours_to_show: 'Graph History',
temperature_unit: 'Temperature Unit'
}; };
return labels[schema.name] || schema.name; return labels[schema.name] || schema.name;
} }
@ -89,6 +91,7 @@ class AirQualityCard extends HTMLElement {
this._config = { this._config = {
name: 'Air Quality', name: 'Air Quality',
hours_to_show: 24, hours_to_show: 24,
temperature_unit: 'F',
...config ...config
}; };
this._rendered = false; this._rendered = false;
@ -204,7 +207,22 @@ class AirQualityCard extends HTMLElement {
return '#ff9800'; return '#ff9800';
} }
_isCelsius() {
return this._config.temperature_unit === 'C';
}
_getTempUnit() {
return this._isCelsius() ? '°C' : '°F';
}
_getTempColor(value) { _getTempColor(value) {
if (this._isCelsius()) {
if (value < 18) return '#2196f3';
if (value < 20) return '#03a9f4';
if (value < 22) return '#4caf50';
if (value < 24) return '#ff9800';
return '#f44336';
}
if (value < 65) return '#2196f3'; if (value < 65) return '#2196f3';
if (value < 68) return '#03a9f4'; if (value < 68) return '#03a9f4';
if (value < 72) return '#4caf50'; if (value < 72) return '#4caf50';
@ -571,7 +589,7 @@ class AirQualityCard extends HTMLElement {
<div class="graph-container" id="temperature-graph-container" data-entity="${this._config.temperature_entity}"> <div class="graph-container" id="temperature-graph-container" data-entity="${this._config.temperature_entity}">
<div class="graph-header"> <div class="graph-header">
<span class="graph-label">Temperature</span> <span class="graph-label">Temperature</span>
<span class="graph-value" id="temperature-value">-- <span class="unit">°F</span><span class="status" id="temperature-status"></span></span> <span class="graph-value" id="temperature-value">-- <span class="unit">${this._getTempUnit()}</span><span class="status" id="temperature-status"></span></span>
</div> </div>
<div class="graph-wrapper"> <div class="graph-wrapper">
<div class="graph" id="temperature-graph"> <div class="graph" id="temperature-graph">
@ -704,15 +722,23 @@ class AirQualityCard extends HTMLElement {
// Update Temperature // Update Temperature
if (temp !== null) { if (temp !== null) {
const tempColor = this._getTempColor(temp); const tempColor = this._getTempColor(temp);
const tempUnit = this._getTempUnit();
const tempValueEl = this.shadowRoot.getElementById('temperature-value'); const tempValueEl = this.shadowRoot.getElementById('temperature-value');
if (tempValueEl) { if (tempValueEl) {
tempValueEl.innerHTML = `${Math.round(temp)} <span class="unit">°F</span><span class="status" id="temperature-status"></span>`; tempValueEl.innerHTML = `${Math.round(temp)} <span class="unit">${tempUnit}</span><span class="status" id="temperature-status"></span>`;
const statusEl = tempValueEl.querySelector('.status'); const statusEl = tempValueEl.querySelector('.status');
let tempStatus = 'Comfortable'; let tempStatus = 'Comfortable';
if (this._isCelsius()) {
if (temp < 18) tempStatus = 'Cold';
else if (temp < 20) tempStatus = 'Cool';
else if (temp > 24) tempStatus = 'Hot';
else if (temp > 22) tempStatus = 'Warm';
} else {
if (temp < 65) tempStatus = 'Cold'; if (temp < 65) tempStatus = 'Cold';
else if (temp < 68) tempStatus = 'Cool'; else if (temp < 68) tempStatus = 'Cool';
else if (temp > 76) tempStatus = 'Hot'; else if (temp > 76) tempStatus = 'Hot';
else if (temp > 72) tempStatus = 'Warm'; else if (temp > 72) tempStatus = 'Warm';
}
statusEl.textContent = tempStatus; statusEl.textContent = tempStatus;
statusEl.style.background = tempColor + '22'; statusEl.style.background = tempColor + '22';
statusEl.style.color = tempColor; statusEl.style.color = tempColor;
@ -734,7 +760,10 @@ class AirQualityCard extends HTMLElement {
this._renderGraph('humidity', this._history.humidity, this._getHumidityColor.bind(this), 0, 100, '%'); this._renderGraph('humidity', this._history.humidity, this._getHumidityColor.bind(this), 0, 100, '%');
} }
if (this._config.temperature_entity && this._history.temperature.length) { if (this._config.temperature_entity && this._history.temperature.length) {
this._renderGraph('temperature', this._history.temperature, this._getTempColor.bind(this), 50, 90, '°F'); const tempUnit = this._getTempUnit();
const tempMin = this._isCelsius() ? 10 : 50;
const tempMax = this._isCelsius() ? 32 : 90;
this._renderGraph('temperature', this._history.temperature, this._getTempColor.bind(this), tempMin, tempMax, tempUnit);
} }
this._setupGraphInteractions(); this._setupGraphInteractions();
@ -915,7 +944,7 @@ class AirQualityCard extends HTMLElement {
if (valueEl) { if (valueEl) {
let displayValue; let displayValue;
if (data.unit === 'ppm') displayValue = Math.round(closest.value); if (data.unit === 'ppm') displayValue = Math.round(closest.value);
else if (data.unit === '%' || data.unit === '°F') displayValue = Math.round(closest.value); else if (data.unit === '%' || data.unit === '°F' || data.unit === '°C') displayValue = Math.round(closest.value);
else displayValue = closest.value.toFixed(1); else displayValue = closest.value.toFixed(1);
valueEl.textContent = `${displayValue} ${data.unit}`; valueEl.textContent = `${displayValue} ${data.unit}`;
valueEl.style.color = closest.color; valueEl.style.color = closest.color;
@ -975,6 +1004,7 @@ if (LitElement && !customElements.get('air-quality-card-editor')) {
this._config = { this._config = {
name: 'Air Quality', name: 'Air Quality',
hours_to_show: 24, hours_to_show: 24,
temperature_unit: 'F',
...config ...config
}; };
} }
@ -988,7 +1018,8 @@ if (LitElement && !customElements.get('air-quality-card-editor')) {
temperature_entity: 'Temperature Sensor (optional)', temperature_entity: 'Temperature Sensor (optional)',
air_quality_entity: 'Air Quality Index (optional)', air_quality_entity: 'Air Quality Index (optional)',
recommendation_entity: 'Recommendation Sensor (optional)', recommendation_entity: 'Recommendation Sensor (optional)',
hours_to_show: 'Graph History (hours)' hours_to_show: 'Graph History (hours)',
temperature_unit: 'Temperature Unit'
}; };
return labels[schema.name] || schema.name; return labels[schema.name] || schema.name;
} }
@ -1002,7 +1033,8 @@ if (LitElement && !customElements.get('air-quality-card-editor')) {
{ name: 'temperature_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'temperature_entity', selector: { entity: { domain: 'sensor' } } },
{ name: 'air_quality_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'air_quality_entity', selector: { entity: { domain: 'sensor' } } },
{ name: 'recommendation_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'recommendation_entity', selector: { entity: { domain: 'sensor' } } },
{ name: 'hours_to_show', selector: { number: { min: 1, max: 168, mode: 'box' } } } { name: 'hours_to_show', selector: { number: { min: 1, max: 168, mode: 'box' } } },
{ name: 'temperature_unit', selector: { select: { options: [{ value: 'F', label: 'Fahrenheit (°F)' }, { value: 'C', label: 'Celsius (°C)' }], mode: 'dropdown' } } }
]; ];
} }