UNPKG

meteoalarm-card

Version:

Meteoalarm card for Home Assistant Lovelace UI

303 lines (283 loc) 8.39 kB
import { HassEntity } from 'home-assistant-js-websocket'; import { MeteoalarmAlert, MeteoalarmEventType, MeteoalarmIntegration, MeteoalarmIntegrationEntityType, MeteoalarmIntegrationMetadata, MeteoalarmLevelType, } from '../types'; type EnvCanadaEntity = HassEntity & { attributes: { attribution: string; }; }; export enum EnvCanadaEntityType { Warning, Watch, Statement, Advisory, } const ATTRIBUTION_EN = 'Data provided by Environment Canada'; const ATTRIBUTION_FR = 'Données fournies par Environnement Canada'; export default class EnvironmentCanada implements MeteoalarmIntegration { public get metadata(): MeteoalarmIntegrationMetadata { return { key: 'env_canada', name: 'Environment Canada', type: MeteoalarmIntegrationEntityType.WarningWatchStatementAdvisory, returnHeadline: false, returnMultipleAlerts: true, entitiesCount: 4, monitoredConditions: [...new Set(this.eventTypes.map((e) => e.type))], }; } public supports(entity: EnvCanadaEntity): boolean { const isStateNumber = !Number.isNaN(Number(entity.state)); return ( [ATTRIBUTION_EN, ATTRIBUTION_FR].includes(entity.attributes.attribution) && this.getEntityType(entity) !== undefined && isStateNumber ); } public alertActive(entity: EnvCanadaEntity): boolean { return Number(entity.state) > 0; } private get eventTypes(): { en: string; fr: string; type: MeteoalarmEventType }[] { // English from: https://www.canada.ca/en/environment-climate-change/services/types-weather-forecasts-use/public/criteria-alerts.html // French from : https://www.canada.ca/fr/environnement-changement-climatique/services/types-previsions-meteorologiques-utilisation/publiques/criteres-alertes-meteo.html return [ { en: 'Arctic Outflow', fr: 'Poussée d’air Arctique', type: MeteoalarmEventType.SnowIce, }, { en: 'Blizzard', fr: 'Blizzard', type: MeteoalarmEventType.SnowIce, }, { en: 'Blowing Snow', fr: 'Poudrerie', type: MeteoalarmEventType.SnowIce, }, { en: 'Dust Storm', fr: 'Tempête de Poussière', type: MeteoalarmEventType.Dust, }, { en: 'Extreme Cold', fr: 'Froid Extrême', type: MeteoalarmEventType.LowTemperature, }, { en: 'Flash Freeze', fr: 'Refroidissement Soudain', type: MeteoalarmEventType.SnowIce, }, { en: 'Fog', fr: 'Brouillard', type: MeteoalarmEventType.Fog, }, { en: 'Freezing Drizzle', fr: 'Bruine Verglaçante', type: MeteoalarmEventType.SnowIce, }, { en: 'Freezing Rain', fr: 'Pluie Verglaçante', type: MeteoalarmEventType.SnowIce, }, { en: 'Frost', fr: 'Gel', type: MeteoalarmEventType.SnowIce, }, { en: 'Heat', fr: 'Chaleur', type: MeteoalarmEventType.HighTemperature, }, { en: 'Hurricane', fr: 'Ouragan', type: MeteoalarmEventType.Hurricane, }, { en: 'Rainfall', fr: 'Pluie', type: MeteoalarmEventType.Rain, }, { en: 'Severe Thunderstorm', fr: 'Orages Violents', type: MeteoalarmEventType.Thunderstorms, }, { en: 'Smog', fr: 'Smog', type: MeteoalarmEventType.AirQuality, }, { en: 'Snowfall', fr: 'Neige', type: MeteoalarmEventType.SnowIce, }, { en: 'Snow Squall', fr: 'Bourrasques de Neige', type: MeteoalarmEventType.SnowIce, }, { en: 'Storm Surge', fr: 'Onde de Tempête', type: MeteoalarmEventType.Thunderstorms, }, { en: 'Tornado', fr: 'Tornade', type: MeteoalarmEventType.Tornado, }, { en: 'Tropical Storm', fr: 'Tempête Tropicale', type: MeteoalarmEventType.Hurricane, }, { en: 'Tsunami', fr: 'Tsunami', type: MeteoalarmEventType.Tsunami, }, { en: 'Weather', fr: 'Météorologique', type: MeteoalarmEventType.Unknown, }, { en: 'Wind', fr: 'Vents', type: MeteoalarmEventType.Wind, }, { en: 'Winter Storm', fr: 'Tempête Hivernale', type: MeteoalarmEventType.SnowIce, }, { en: 'Special Weather', fr: 'Météorologique Spécial', type: MeteoalarmEventType.Unknown, }, { en: 'Special Air Quality', fr: "Spécial Sur La Qualité De L'Air", type: MeteoalarmEventType.AirQuality, }, ]; } private get entityTypeTranslation(): { en: string[]; fr: string[]; type: EnvCanadaEntityType }[] { // English from: https://www.canada.ca/en/environment-climate-change/services/types-weather-forecasts-use/public/criteria-alerts.html // French from : https://www.canada.ca/fr/environnement-changement-climatique/services/types-previsions-meteorologiques-utilisation/publiques/criteres-alertes-meteo.html return [ { type: EnvCanadaEntityType.Warning, en: ['Warning'], fr: ['Avertissement De', 'Avertissement D'], }, { type: EnvCanadaEntityType.Watch, en: ['Watch'], fr: ['Veille De', "Veille D'"], }, { type: EnvCanadaEntityType.Statement, en: ['Statement'], fr: ['Bulletin'], }, { type: EnvCanadaEntityType.Advisory, en: ['Advisory'], fr: ['Avis De', "Avis D'", 'Avis'], }, ]; } /** * Alert name in the integration are combined event type * and sensor from which it was sent like: * Wind + Warning = Wind Warning * This transforms this back to event type */ private praseAlertName(alertName: string, type: EnvCanadaEntityType, isFrench: boolean) { const prefixTranslation = this.entityTypeTranslation.find((t) => t.type == type)!; const prefixes = isFrench ? prefixTranslation.fr : prefixTranslation.en; const prefix = prefixes.find((p) => alertName.includes(p)); if (prefix == undefined) { throw new Error( `Failed to match one of the known prefixes to alert name! ` + `Was looking for [ "${prefixes.join('", "')}" ] and failed ` + `(isFrench=${isFrench})`, ); } alertName = alertName.replace(prefix, '').trim(); return this.eventTypes.find((e) => { return (isFrench && e.fr == alertName) || (!isFrench && e.en == alertName); }); } public getAlerts(entity: EnvCanadaEntity): MeteoalarmAlert[] { const warningCount = Number(entity.state); const result: MeteoalarmAlert[] = []; const type = this.getEntityType(entity)!; for (let i = 1; i < warningCount + 1; i++) { const alertName = entity.attributes[`alert_${i}`] as string; const isFrench = entity.attributes.attribution == 'Données fournies par Environnement Canada'; const alert = this.praseAlertName(alertName, type, isFrench); if (alert) { result.push({ level: this.getLevelFromType(type), event: alert.type, }); } else { throw new Error( `Unknown Environnement Canada alert encountered! Name: ${alertName} (isFrench=${isFrench})`, ); } } return result; } private getEntityType(entity: HassEntity): EnvCanadaEntityType | undefined { // It's actually a sketchy solution to this, entity type can be detected by // entity_id or friendly_name so it loops thought both of them for (const attribute of [ entity.entity_id, entity.attributes.friendly_name?.toLocaleLowerCase(), ]) { if (!attribute) continue; if (attribute.includes('warnings')) { return EnvCanadaEntityType.Warning; } else if (attribute.includes('watches')) { return EnvCanadaEntityType.Watch; } else if (attribute.includes('statements')) { return EnvCanadaEntityType.Statement; } else if (attribute.includes('advisory')) { return EnvCanadaEntityType.Advisory; } } return undefined; } private getLevelFromType(type: EnvCanadaEntityType): MeteoalarmLevelType { if (type == EnvCanadaEntityType.Warning) { return MeteoalarmLevelType.Red; } else if (type == EnvCanadaEntityType.Watch) { return MeteoalarmLevelType.Orange; } else if (type == EnvCanadaEntityType.Statement || type == EnvCanadaEntityType.Advisory) { return MeteoalarmLevelType.Yellow; } else { // This should never happen but is required in order for TS to stop complaining return MeteoalarmLevelType.Red; } } }