diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml deleted file mode 100644 index 3387332..0000000 --- a/.github/workflows/validate.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Validate - -on: - push: - pull_request: - schedule: - - cron: "0 0 * * *" - workflow_dispatch: - -jobs: - validate-hacs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: HACS Validation - uses: hacs/action@main - with: - category: plugin diff --git a/README.md b/README.md index c2cc01a..0f246b8 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ temperature_entity: sensor.air_quality_temperature air_quality_entity: sensor.air_quality_index recommendation_entity: sensor.air_quality_recommendation hours_to_show: 24 -temperature_unit: C ``` ### Configuration Options @@ -70,7 +69,6 @@ temperature_unit: C | `air_quality_entity` | string | No | - | Overall air quality index entity | | `recommendation_entity` | string | No | - | Recommendation template sensor | | `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 diff --git a/air-quality-card.js b/air-quality-card.js index 81b4ba0..1492551 100644 --- a/air-quality-card.js +++ b/air-quality-card.js @@ -6,7 +6,7 @@ * https://github.com/KadenThomp36/air-quality-card */ -const CARD_VERSION = '2.2.0'; +const CARD_VERSION = '2.1.0'; class AirQualityCard extends HTMLElement { // Visual editor using getConfigForm (preferred modern approach) @@ -21,13 +21,6 @@ class AirQualityCard extends HTMLElement { { name: 'pm25_entity', selector: { entity: { domain: 'sensor' } } }, ] }, - { - type: 'grid', - schema: [ - { name: 'hcho_entity', selector: { entity: { domain: 'sensor' } } }, - { name: 'tvoc_entity', selector: { entity: { domain: 'sensor' } } }, - ] - }, { type: 'grid', schema: [ @@ -42,7 +35,6 @@ class AirQualityCard extends HTMLElement { { name: 'air_quality_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: 'temperature_unit', selector: { select: { options: [{ value: 'F', label: 'Fahrenheit (°F)' }, { value: 'C', label: 'Celsius (°C)' }], mode: 'dropdown' } } }, ] } ], @@ -54,11 +46,8 @@ class AirQualityCard extends HTMLElement { humidity_entity: 'Humidity Sensor (optional)', temperature_entity: 'Temperature Sensor (optional)', air_quality_entity: 'Air Quality Index (optional)', - hcho_entity: 'Formaldehyde (HCHO; CH2O) Sensor (optional)', - tvoc_entity: 'Volatile Organic Compounds (tVOC) Sensor (optional)', recommendation_entity: 'Recommendation Sensor (optional)', - hours_to_show: 'Graph History', - temperature_unit: 'Temperature Unit' + hours_to_show: 'Graph History' }; return labels[schema.name] || schema.name; } @@ -100,7 +89,6 @@ class AirQualityCard extends HTMLElement { this._config = { name: 'Air Quality', hours_to_show: 24, - temperature_unit: 'F', ...config }; this._rendered = false; @@ -121,8 +109,6 @@ class AirQualityCard extends HTMLElement { let size = 3; // Base size for header and recommendation if (this._config.co2_entity) size += 1; if (this._config.pm25_entity) size += 1; - if (this._config.hcho_entity) size += 1; - if (this._config.tvoc_entity) size += 1; if (this._config.humidity_entity) size += 1; if (this._config.temperature_entity) size += 1; return size; @@ -146,14 +132,6 @@ class AirQualityCard extends HTMLElement { promises.push(this._fetchHistory(this._config.pm25_entity, startTime, endTime)); keys.push('pm25'); } - if (this._config.hcho_entity) { - promises.push(this._fetchHistory(this._config.hcho_entity, startTime, endTime)); - keys.push('hcho'); - } - if (this._config.tvoc_entity) { - promises.push(this._fetchHistory(this._config.tvoc_entity, startTime, endTime)); - keys.push('voc'); - } if (this._config.humidity_entity) { promises.push(this._fetchHistory(this._config.humidity_entity, startTime, endTime)); keys.push('humidity'); @@ -218,22 +196,6 @@ class AirQualityCard extends HTMLElement { return '#f44336'; } - _getHCHOColor(value) { - if (value < 20) return '#4caf50'; - if (value < 50) return '#8bc34a'; - if (value < 100) return '#ffc107'; - if (value < 200) return '#ff9800'; - return '#f44336'; - } - - _getTVOCColor(value) { - if (value < 100) return '#4caf50'; - if (value < 300) return '#8bc34a'; - if (value < 500) return '#ffc107'; - if (value < 1000) return '#ff9800'; - return '#f44336'; - } - _getHumidityColor(value) { if (value < 30) return '#ff9800'; if (value < 40) return '#8bc34a'; @@ -242,22 +204,7 @@ class AirQualityCard extends HTMLElement { return '#ff9800'; } - _isCelsius() { - return this._config.temperature_unit === 'C'; - } - - _getTempUnit() { - return this._isCelsius() ? '°C' : '°F'; - } - _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 < 68) return '#03a9f4'; if (value < 72) return '#4caf50'; @@ -337,8 +284,6 @@ class AirQualityCard extends HTMLElement { _initialRender() { const showCO2 = !!this._config.co2_entity; const showPM25 = !!this._config.pm25_entity; - const showHCHO = !!this._config.hcho_entity; - const showTVOC = !!this._config.tvoc_entity; const showHumidity = !!this._config.humidity_entity; const showTemp = !!this._config.temperature_entity; @@ -601,45 +546,6 @@ class AirQualityCard extends HTMLElement {
` : ''} - ${showHCHO ? ` -
-
- HCHO / CH₂O - -- ppm -
-
-
- -
-
-
-
-
-
-
-
-
- ` : ''} - - ${showTVOC ? ` -
-
- tVOC - -- μg/m³ -
-
-
- -
-
-
-
-
-
-
-
-
- ` : ''} ${showHumidity ? `
@@ -665,7 +571,7 @@ class AirQualityCard extends HTMLElement {
Temperature - -- ${this._getTempUnit()} + -- °F
@@ -691,8 +597,6 @@ class AirQualityCard extends HTMLElement { const co2 = this._config.co2_entity ? this._getNumericState(this._config.co2_entity) : null; const pm25 = this._config.pm25_entity ? this._getNumericState(this._config.pm25_entity) : null; - const hcho = this._config.hcho_entity ? this._getNumericState(this._config.hcho_entity) : null; - const tvoc = this._config.tvoc_entity ? this._getNumericState(this._config.tvoc_entity) : null; const humidity = this._config.humidity_entity ? this._getNumericState(this._config.humidity_entity) : null; const temp = this._config.temperature_entity ? this._getNumericState(this._config.temperature_entity) : null; const recommendation = this._getRecommendation(); @@ -778,34 +682,6 @@ class AirQualityCard extends HTMLElement { } } - // Update HCHO - if (hcho !== null) { - const hchoColor = this._getHCHOColor(hcho); - const hchoValueEl = this.shadowRoot.getElementById('hcho-value'); - if (hchoValueEl) { - hchoValueEl.innerHTML = `${hcho.toFixed(1)} ppb`; - const statusEl = hchoValueEl.querySelector('.status'); - statusEl.textContent = hcho < 20 ? 'Excellent' : hcho < 50 ? 'Good' : hcho < 100 ? 'Moderate' : hcho < 200 ? 'Elevated' : 'Poor'; - statusEl.style.background = hchoColor + '22'; - statusEl.style.color = hchoColor; - hchoValueEl.style.color = hchoColor; - } - } - - // Update tVOC - if (tvoc !== null) { - const tvocColor = this._getTVOCColor(tvoc); - const tvocValueEl = this.shadowRoot.getElementById('tvoc-value'); - if (tvocValueEl) { - tvocValueEl.innerHTML = `${tvoc.toFixed(1)} ppb`; - const statusEl = tvocValueEl.querySelector('.status'); - statusEl.textContent = tvoc < 100 ? 'Excellent' : tvoc < 300 ? 'Good' : tvoc < 500 ? 'Moderate' : tvoc < 1000 ? 'Elevated' : 'Poor'; - statusEl.style.background = tvocColor + '22'; - statusEl.style.color = tvocColor; - tvocValueEl.style.color = tvocColor; - } - } - // Update Humidity if (humidity !== null) { const humidityColor = this._getHumidityColor(humidity); @@ -828,23 +704,15 @@ class AirQualityCard extends HTMLElement { // Update Temperature if (temp !== null) { const tempColor = this._getTempColor(temp); - const tempUnit = this._getTempUnit(); const tempValueEl = this.shadowRoot.getElementById('temperature-value'); if (tempValueEl) { - tempValueEl.innerHTML = `${Math.round(temp)} ${tempUnit}`; + tempValueEl.innerHTML = `${Math.round(temp)} °F`; const statusEl = tempValueEl.querySelector('.status'); 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'; - else if (temp < 68) tempStatus = 'Cool'; - else if (temp > 76) tempStatus = 'Hot'; - else if (temp > 72) tempStatus = 'Warm'; - } + if (temp < 65) tempStatus = 'Cold'; + else if (temp < 68) tempStatus = 'Cool'; + else if (temp > 76) tempStatus = 'Hot'; + else if (temp > 72) tempStatus = 'Warm'; statusEl.textContent = tempStatus; statusEl.style.background = tempColor + '22'; statusEl.style.color = tempColor; @@ -862,20 +730,11 @@ class AirQualityCard extends HTMLElement { if (this._config.pm25_entity && this._history.pm25.length) { this._renderGraph('pm25', this._history.pm25, this._getPM25Color.bind(this), 0, 60, 'μg/m³'); } - if (this._config.hcho_entity && this._history.hcho.length) { - this._renderGraph('hcho', this._history.hcho, this._getHCHOColor.bind(this), 0, 60, 'ppb'); - } - if (this._config.tvoc_entity && this._history.tvoc.length) { - this._renderGraph('tvoc', this._history.tvoc, this._getTVOCColor.bind(this), 0, 60, 'ppb'); - } if (this._config.humidity_entity && this._history.humidity.length) { this._renderGraph('humidity', this._history.humidity, this._getHumidityColor.bind(this), 0, 100, '%'); } if (this._config.temperature_entity && this._history.temperature.length) { - 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._renderGraph('temperature', this._history.temperature, this._getTempColor.bind(this), 50, 90, '°F'); } this._setupGraphInteractions(); @@ -1056,7 +915,7 @@ class AirQualityCard extends HTMLElement { if (valueEl) { let displayValue; if (data.unit === 'ppm') displayValue = Math.round(closest.value); - else if (data.unit === '%' || data.unit === '°F' || data.unit === '°C') displayValue = Math.round(closest.value); + else if (data.unit === '%' || data.unit === '°F') displayValue = Math.round(closest.value); else displayValue = closest.value.toFixed(1); valueEl.textContent = `${displayValue} ${data.unit}`; valueEl.style.color = closest.color; @@ -1116,7 +975,6 @@ if (LitElement && !customElements.get('air-quality-card-editor')) { this._config = { name: 'Air Quality', hours_to_show: 24, - temperature_unit: 'F', ...config }; } @@ -1126,14 +984,11 @@ if (LitElement && !customElements.get('air-quality-card-editor')) { name: 'Card Name', co2_entity: 'CO₂ Sensor', pm25_entity: 'PM2.5 Sensor', - hcho_entity: 'HCHO Sensor (optional)', - tvoc_entity: 'tVOC Sensor (optional)', humidity_entity: 'Humidity Sensor (optional)', temperature_entity: 'Temperature Sensor (optional)', air_quality_entity: 'Air Quality Index (optional)', recommendation_entity: 'Recommendation Sensor (optional)', - hours_to_show: 'Graph History (hours)', - temperature_unit: 'Temperature Unit' + hours_to_show: 'Graph History (hours)' }; return labels[schema.name] || schema.name; } @@ -1143,14 +998,11 @@ if (LitElement && !customElements.get('air-quality-card-editor')) { { name: 'name', selector: { text: {} } }, { name: 'co2_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'pm25_entity', selector: { entity: { domain: 'sensor' } } }, - { name: 'hcho_entity', selector: { entity: { domain: 'sensor' } } }, - { name: 'tvoc_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'humidity_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'temperature_entity', selector: { entity: { domain: 'sensor' } } }, { name: 'air_quality_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: 'temperature_unit', selector: { select: { options: [{ value: 'F', label: 'Fahrenheit (°F)' }, { value: 'C', label: 'Celsius (°C)' }], mode: 'dropdown' } } } + { name: 'hours_to_show', selector: { number: { min: 1, max: 168, mode: 'box' } } } ]; }