diff --git a/demo/src/configs/jimpower/theme.ts b/demo/src/configs/jimpower/theme.ts index 091c472135..8f9e28fe60 100644 --- a/demo/src/configs/jimpower/theme.ts +++ b/demo/src/configs/jimpower/theme.ts @@ -19,6 +19,7 @@ export const demoThemeJimpower = () => ({ "paper-grey-200": "#414A59", "label-badge-background-color": "#2E333A", "paper-card-header-color": "var(--accent-color)", + "sidebar-icon-color": "var(--paper-item-icon-color)", "paper-listbox-background-color": "#2E333A", "table-row-background-color": "#353840", "paper-grey-50": "var(--primary-text-color)", diff --git a/demo/src/configs/teachingbirds/lovelace.ts b/demo/src/configs/teachingbirds/lovelace.ts index c6c585a185..cd591b2e1f 100644 --- a/demo/src/configs/teachingbirds/lovelace.ts +++ b/demo/src/configs/teachingbirds/lovelace.ts @@ -93,7 +93,7 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ type: "icon", tap_action: { action: "navigate", - navigation_path: "/lovelace/traffic", + navigation_path: "/lovelace/home_info", }, icon: "mdi:car", }, @@ -192,6 +192,12 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ ], type: "horizontal-stack", }, + ], + type: "vertical-stack", + }, + { + type: "vertical-stack", + cards: [ { cards: [ { @@ -225,248 +231,180 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ type: "horizontal-stack", }, ], - type: "vertical-stack", + }, + { + entities: [ + "light.outdoor_lights", + { + name: "Yard net", + entity: "light.outdoor_yard_light_net", + }, + "light.bedroom_ceiling_light", + "light.bedside_lamp", + "light.dining_area_ceiling_light_level", + "light.kitchen_ceiling_spotlights_level", + "light.floorlamp_reading_light", + "light.floorlamp_uplight", + "light.hallway_window_light", + "light.isa_ceiling_light", + "light.living_room_ceiling_light_level", + "light.living_room_spotlights_level", + "light.passage_ceiling_spotlights_level", + "light.stairs_lights_lights", + "light.walk_in_closet_lights", + "light.upstairs_hallway_ceiling_light_level", + "light.gateway_light_34ce008bfc4b", + ], + show_empty: false, + type: "entity-filter", + card: { + type: "glance", + show_state: false, + }, + state_filter: ["on"], + }, + { + type: "shopping-list", + }, + { + entities: [ + { + entity: "switch.livingroom_tv", + name: "Tv", + icon: "mdi:television-classic", + }, + // { + // hide_power: true, + // group: true, + // icon: "mdi:television-classic", + // artwork_border: true, + // type: "custom:mini-media-player", + // entity: "media_player.livingroom_tv", + // }, + { + entity: "switch.livingroom_movie_system", + name: "Movie system", + icon: "mdi:movie", + }, + // { + // hide_power: true, + // group: true, + // name: "Movie system", + // icon: "mdi:movie", + // artwork_border: true, + // type: "custom:mini-media-player", + // entity: "media_player.livingroom_movie_system", + // }, + // { + // hide_power: true, + // type: "custom:mini-media-player", + // entity: "media_player.shield", + // group: true, + // icon: "mdi:cast", + // }, + // { + // group: true, + // icon: "mdi:speaker-wireless", + // power_color: true, + // artwork_border: true, + // type: "custom:mini-media-player", + // entity: "media_player.sonos", + // }, + // { + // group: true, + // name: "Chromecast Bedroom", + // icon: "mdi:cast", + // artwork_border: true, + // type: "custom:mini-media-player", + // entity: "media_player.sovrum", + // }, + ], + type: "entities", + }, + + { + image: "/assets/teachingbirds/plants.png", + elements: [ + { + style: { + top: "7%", + "--ha-label-badge-font-size": "1em", + left: "2%", + transform: "none", + }, + type: "state-badge", + entity: "sensor.small_chili_moisture", + }, + { + style: { + top: "7%", + "--ha-label-badge-font-size": "1em", + left: "17%", + transform: "none", + }, + type: "state-badge", + entity: "sensor.big_chili_moisture", + }, + { + style: { + top: "7%", + "--ha-label-badge-font-size": "1em", + left: "32%", + transform: "none", + }, + type: "state-badge", + entity: "sensor.herbs_moisture", + }, + { + style: { + top: "12%", + "--ha-label-badge-font-size": "1em", + left: "92%", + }, + type: "state-label", + entity: "sensor.greenhouse_temperature", + }, + ], + type: "picture-elements", + }, + { + // show_name: false, + // entity: "camera.stockholm_meteogram", + // type: "picture-entity", + // show_state: false, + type: "picture", + image: "/assets/teachingbirds/meteogram.png", }, { cards: [ { - cards: [ - // { - // entities: [ - // { - // name: "Front door lock", - // entity: "sensor.front_door_lock", - // }, - // { - // name: "Yard door lock", - // entity: "sensor.yard_door_lock", - // }, - // "sensor.front_door", - // "sensor.back_door", - // "sensor.backyard_door", - // "sensor.balcony_door", - // "sensor.yard_door", - // { - // name: "Dining area", - // entity: "sensor.dining_area_window", - // }, - // { - // name: "Bedroom", - // entity: "sensor.bedroom_window", - // }, - // { - // name: "Ring motion", - // entity: "sensor.front_door_outdoor_movement", - // }, - // "sensor.hallway_movement", - // "sensor.passage_movement", - // "sensor.upstairs_hallway_movement", - // "sensor.living_room_movement", - // "sensor.back_door_camera_movement", - // { - // name: "Storage door", - // entity: "sensor.yard_storage_door", - // }, - // "sensor.water_heater", - // "sensor.kitchen_sink", - // "binary_sensor.smoke_sensor_158d0001d37bdd", - // "binary_sensor.smoke_sensor_158d0001d37be5", - // "binary_sensor.smoke_sensor_158d0001d37c82", - // ], - // show_empty: false, - // type: "entity-filter", - // card: { - // type: "glance", - // show_state: false, - // }, - // state_filter: [ - // "Open", - // "Movement detected", - // "Leaking", - // "Unlocked", - // "on", - // ], - // }, - { - entities: [ - "light.outdoor_lights", - { - name: "Yard net", - entity: "light.outdoor_yard_light_net", - }, - "light.bedroom_ceiling_light", - "light.bedside_lamp", - "light.dining_area_ceiling_light_level", - "light.kitchen_ceiling_spotlights_level", - "light.floorlamp_reading_light", - "light.floorlamp_uplight", - "light.hallway_window_light", - "light.isa_ceiling_light", - "light.living_room_ceiling_light_level", - "light.living_room_spotlights_level", - "light.passage_ceiling_spotlights_level", - "light.stairs_lights_lights", - "light.walk_in_closet_lights", - "light.upstairs_hallway_ceiling_light_level", - "light.gateway_light_34ce008bfc4b", - ], - show_empty: false, - type: "entity-filter", - card: { - type: "glance", - show_state: false, - }, - state_filter: ["on"], - }, - ], - type: "vertical-stack", + type: "gauge", + severity: { + green: 0, + yellow: 2, + red: 3, + }, + min: 0, + max: 6, + title: "Downstairs", + measurement: "visits", + entity: "counter.litterbox_downstairs_visits", }, { - type: "shopping-list", - }, - { - entities: [ - { - entity: "switch.livingroom_tv", - name: "Tv", - icon: "mdi:television-classic", - }, - // { - // hide_power: true, - // group: true, - // icon: "mdi:television-classic", - // artwork_border: true, - // type: "custom:mini-media-player", - // entity: "media_player.livingroom_tv", - // }, - { - entity: "switch.livingroom_movie_system", - name: "Movie system", - icon: "mdi:movie", - }, - // { - // hide_power: true, - // group: true, - // name: "Movie system", - // icon: "mdi:movie", - // artwork_border: true, - // type: "custom:mini-media-player", - // entity: "media_player.livingroom_movie_system", - // }, - // { - // hide_power: true, - // type: "custom:mini-media-player", - // entity: "media_player.shield", - // group: true, - // icon: "mdi:cast", - // }, - // { - // group: true, - // icon: "mdi:speaker-wireless", - // power_color: true, - // artwork_border: true, - // type: "custom:mini-media-player", - // entity: "media_player.sonos", - // }, - // { - // group: true, - // name: "Chromecast Bedroom", - // icon: "mdi:cast", - // artwork_border: true, - // type: "custom:mini-media-player", - // entity: "media_player.sovrum", - // }, - ], - type: "entities", + type: "gauge", + severity: { + green: 0, + yellow: 2, + red: 3, + }, + min: 0, + max: 6, + title: "Upstairs", + measurement: "visits", + entity: "counter.litterbox_upstairs_visits", }, ], - type: "vertical-stack", - }, - { - cards: [ - { - image: "/assets/teachingbirds/plants.png", - elements: [ - { - style: { - top: "30%", - "--ha-label-badge-font-size": "1em", - left: "10%", - }, - type: "state-badge", - entity: "sensor.small_chili_moisture", - }, - { - style: { - top: "30%", - "--ha-label-badge-font-size": "1em", - left: "25%", - }, - type: "state-badge", - entity: "sensor.big_chili_moisture", - }, - { - style: { - top: "30%", - "--ha-label-badge-font-size": "1em", - left: "40%", - }, - type: "state-badge", - entity: "sensor.herbs_moisture", - }, - { - style: { - top: "12%", - "--ha-label-badge-font-size": "1em", - left: "92%", - }, - type: "state-label", - entity: "sensor.greenhouse_temperature", - }, - ], - type: "picture-elements", - }, - { - // show_name: false, - // entity: "camera.stockholm_meteogram", - // type: "picture-entity", - // show_state: false, - type: "picture", - image: "/assets/teachingbirds/meteogram.png", - }, - { - cards: [ - { - type: "gauge", - severity: { - green: 0, - yellow: 2, - red: 3, - }, - min: 0, - max: 6, - title: "Downstairs", - measurement: "visits", - entity: "counter.litterbox_downstairs_visits", - }, - { - type: "gauge", - severity: { - green: 0, - yellow: 2, - red: 3, - }, - min: 0, - max: 6, - title: "Upstairs", - measurement: "visits", - entity: "counter.litterbox_upstairs_visits", - }, - ], - type: "horizontal-stack", - }, - ], - type: "vertical-stack", + type: "horizontal-stack", }, ], path: "home", @@ -478,75 +416,75 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ { cards: [ { - cards: [ - { - entity: "script.air_cleaner_quiet", - type: "entity-button", - name: "AC bed", - tap_action: { - action: "call-service", - service_data: { - entity_id: "script.air_cleaner_quiet", - }, - service: "script.turn_on", - }, - icon: "mdi:fan-off", + entity: "script.air_cleaner_quiet", + type: "entity-button", + name: "AC bed", + tap_action: { + action: "call-service", + service_data: { + entity_id: "script.air_cleaner_quiet", }, - { - entity: "script.air_cleaner_auto", - type: "entity-button", - name: "AC bed", - tap_action: { - action: "call-service", - service_data: { - entity_id: "script.air_cleaner_auto", - }, - service: "script.turn_on", - }, - icon: "mdi:fan", - }, - { - entity: "script.air_cleaner_turbo", - type: "entity-button", - name: "AC bed", - tap_action: { - action: "call-service", - service_data: { - entity_id: "script.air_cleaner_turbo", - }, - service: "script.turn_on", - }, - icon: "mdi:run-fast", - }, - { - entity: "script.ac_off", - type: "entity-button", - name: "AC", - tap_action: { - action: "call-service", - service_data: { - entity_id: "script.ac_off", - }, - service: "script.turn_on", - }, - icon: "mdi:fan-off", - }, - { - entity: "script.ac_on", - type: "entity-button", - name: "AC", - tap_action: { - action: "call-service", - service_data: { - entity_id: "script.ac_on", - }, - service: "script.turn_on", - }, - icon: "mdi:fan", - }, - ], - type: "horizontal-stack", + service: "script.turn_on", + }, + icon: "mdi:fan-off", }, + { + entity: "script.air_cleaner_auto", + type: "entity-button", + name: "AC bed", + tap_action: { + action: "call-service", + service_data: { + entity_id: "script.air_cleaner_auto", + }, + service: "script.turn_on", + }, + icon: "mdi:fan", + }, + { + entity: "script.air_cleaner_turbo", + type: "entity-button", + name: "AC bed", + tap_action: { + action: "call-service", + service_data: { + entity_id: "script.air_cleaner_turbo", + }, + service: "script.turn_on", + }, + icon: "mdi:run-fast", + }, + { + entity: "script.ac_off", + type: "entity-button", + name: "AC", + tap_action: { + action: "call-service", + service_data: { + entity_id: "script.ac_off", + }, + service: "script.turn_on", + }, + icon: "mdi:fan-off", + }, + { + entity: "script.ac_on", + type: "entity-button", + name: "AC", + tap_action: { + action: "call-service", + service_data: { + entity_id: "script.ac_on", + }, + service: "script.turn_on", + }, + icon: "mdi:fan", + }, + ], + type: "horizontal-stack", + }, + { + cards: [ { cards: [ { @@ -595,91 +533,100 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ ], type: "horizontal-stack", }, - { - entities: [ - { - name: "Vacation", - entity: "input_boolean.vacation_mode", - }, - "input_boolean.cleaning_day", - "input_boolean.guest_mode", - { - name: "Isa Mode", - tap_action: { - action: "toggle", - }, - entity: "input_boolean.isa_mode", - }, - ], - show_header_toggle: false, - type: "glance", - }, - { - entities: [ - "sensor.pollen_bjork", - "sensor.pollen_gras", - "sensor.pollen_grabo", - ], - type: "glance", - }, ], type: "vertical-stack", }, { - cards: [ + entities: [ { - states: ["arm_home", "arm_away", "arm_night"], - type: "alarm-panel", - entity: "alarm_control_panel.house", + name: "Vacation", + entity: "input_boolean.vacation_mode", + tap_action: { + action: "toggle", + }, }, { - entities: [ - { - entity: "sensor.front_door", - secondary_info: "last-changed", - }, - { - entity: "sensor.back_door", - secondary_info: "last-changed", - }, - { - entity: "sensor.yard_door", - secondary_info: "last-changed", - }, - { - entity: "sensor.balcony_door", - secondary_info: "last-changed", - }, - { - entity: "sensor.dining_area_window", - secondary_info: "last-changed", - }, - { - entity: "sensor.bedroom_window", - secondary_info: "last-changed", - }, - { - entity: "sensor.passage_movement", - secondary_info: "last-changed", - }, - { - entity: "sensor.upstairs_hallway_movement", - secondary_info: "last-changed", - }, - { - entity: "binary_sensor.stefans_room_motion", - secondary_info: "last-changed", - }, - { - entity: "sensor.ring_front_door_last_motion", - secondary_info: "last-changed", - }, - ], - type: "entities", + entity: "input_boolean.cleaning_day", + tap_action: { + action: "toggle", + }, + }, + { + entity: "input_boolean.guest_mode", + tap_action: { + action: "toggle", + }, + }, + { + name: "Isa Mode", + tap_action: { + action: "toggle", + }, + entity: "input_boolean.isa_mode", }, ], - type: "vertical-stack", + show_header_toggle: false, + type: "glance", }, + { + entities: [ + "sensor.pollen_bjork", + "sensor.pollen_gras", + "sensor.pollen_grabo", + ], + type: "glance", + }, + { + states: ["arm_home", "arm_away", "arm_night"], + type: "alarm-panel", + entity: "alarm_control_panel.house", + }, + { + entities: [ + { + entity: "sensor.front_door", + secondary_info: "last-changed", + }, + { + entity: "sensor.back_door", + secondary_info: "last-changed", + }, + { + entity: "sensor.yard_door", + secondary_info: "last-changed", + }, + { + entity: "sensor.balcony_door", + secondary_info: "last-changed", + }, + { + entity: "sensor.dining_area_window", + secondary_info: "last-changed", + }, + { + entity: "sensor.bedroom_window", + secondary_info: "last-changed", + }, + { + entity: "sensor.passage_movement", + secondary_info: "last-changed", + }, + { + entity: "sensor.upstairs_hallway_movement", + secondary_info: "last-changed", + }, + { + entity: "binary_sensor.stefans_room_motion", + secondary_info: "last-changed", + }, + { + entity: "sensor.ring_front_door_last_motion", + secondary_info: "last-changed", + }, + ], + type: "entities", + }, + { cards: [ { @@ -729,19 +676,16 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ cards: [ { entity: "scene.morning_lights", - hold_action: { + tap_action: { action: "call-service", service: "script.goodnight", }, type: "entity-button", - tap_action: { - action: "none", - }, icon: "mdi:weather-night", }, { entity: "scene.morning_lights", - hold_action: { + tap_action: { action: "call-service", service_data: { entity_id: "scene.morning_lights", @@ -749,14 +693,11 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ service: "scene.turn_on", }, type: "entity-button", - tap_action: { - action: "none", - }, icon: "mdi:coffee-outline", }, { entity: "scene.movie_time", - hold_action: { + tap_action: { action: "call-service", service_data: { entity_id: "scene.movie_time", @@ -764,9 +705,6 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ service: "scene.turn_on", }, type: "entity-button", - tap_action: { - action: "none", - }, icon: "mdi:television-classic", }, ], @@ -820,32 +758,26 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({ cards: [ { entity: "light.downstairs_lights", - hold_action: { + tap_action: { action: "call-service", service_data: { entity_id: "light.downstairs_lights", }, - service: "light.turn_off", + service: "light.toggle", }, type: "entity-button", - tap_action: { - action: "none", - }, icon: "mdi:page-layout-footer", }, { entity: "light.upstairs_lights", - hold_action: { + tap_action: { action: "call-service", service_data: { entity_id: "light.upstairs_lights", }, - service: "light.turn_off", + service: "light.toggle", }, type: "entity-button", - tap_action: { - action: "none", - }, icon: "mdi:page-layout-header", }, ], diff --git a/demo/src/ha-demo.ts b/demo/src/ha-demo.ts index 71174d0ada..97f1b71617 100644 --- a/demo/src/ha-demo.ts +++ b/demo/src/ha-demo.ts @@ -7,6 +7,9 @@ import { selectedDemoConfig } from "./configs/demo-configs"; import { mockTranslations } from "./stubs/translations"; import { mockHistory } from "./stubs/history"; import { mockShoppingList } from "./stubs/shopping_list"; +import { mockSystemLog } from "./stubs/system_log"; +import { mockTemplate } from "./stubs/template"; +import { mockEvents } from "./stubs/events"; class HaDemo extends HomeAssistant { protected async _handleConnProm() { @@ -24,6 +27,9 @@ class HaDemo extends HomeAssistant { mockTranslations(hass); mockHistory(hass); mockShoppingList(hass); + mockSystemLog(hass); + mockTemplate(hass); + mockEvents(hass); selectedDemoConfig.then((conf) => { hass.addEntities(conf.entities()); if (conf.theme) { diff --git a/demo/src/stubs/events.ts b/demo/src/stubs/events.ts new file mode 100644 index 0000000000..2e371bdeb1 --- /dev/null +++ b/demo/src/stubs/events.ts @@ -0,0 +1,5 @@ +import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; + +export const mockEvents = (hass: MockHomeAssistant) => { + hass.mockAPI("events", () => []); +}; diff --git a/demo/src/stubs/history.ts b/demo/src/stubs/history.ts index c194f36d36..c0364760a8 100644 --- a/demo/src/stubs/history.ts +++ b/demo/src/stubs/history.ts @@ -1,5 +1,138 @@ import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; +import { HassEntity } from "home-assistant-js-websocket"; -export const mockHistory = (hass: MockHomeAssistant) => { - hass.mockAPI(new RegExp("history/period/.+"), () => []); +interface HistoryQueryParams { + filter_entity_id: string; + end_time: string; +} + +const parseQuery = (queryString: string) => { + const query: any = {}; + const items = queryString.split("&"); + for (const item of items) { + const parts = item.split("="); + const key = decodeURIComponent(parts[0]); + const value = parts.length > 1 ? decodeURIComponent(parts[1]) : undefined; + query[key] = value; + } + return query as T; +}; + +const getTime = (minutesAgo) => { + const ts = new Date(Date.now() - minutesAgo * 60 * 1000); + return ts.toISOString(); +}; + +const randomTimeAdjustment = (diff) => Math.random() * diff - diff / 2; + +const maxTime = 1440; + +const generateHistory = (state, deltas) => { + const changes = + typeof deltas[0] === "object" + ? deltas + : deltas.map((st) => ({ state: st })); + + const timeDiff = 900 / changes.length; + + return changes.map((change, index) => { + let attributes; + if (!change.attributes && !state.attributes) { + attributes = {}; + } else if (!change.attributes) { + attributes = state.attributes; + } else if (!state.attributes) { + attributes = change.attributes; + } else { + attributes = { ...state.attributes, ...change.attributes }; + } + + const time = + index === 0 + ? getTime(maxTime) + : getTime(maxTime - index * timeDiff + randomTimeAdjustment(timeDiff)); + + return { + attributes, + entity_id: state.entity_id, + state: change.state || state.state, + last_changed: time, + last_updated: time, + }; + }); +}; + +const incrementalUnits = ["clients", "queries", "ads"]; + +export const mockHistory = (mockHass: MockHomeAssistant) => { + mockHass.mockAPI(new RegExp("history/period/.+"), ( + hass, + // @ts-ignore + method, + path, + // @ts-ignore + parameters + ) => { + const params = parseQuery(path.split("?")[1]); + const entities = params.filter_entity_id.split(","); + + const results: HassEntity[][] = []; + + for (const entityId of entities) { + const state = hass.states[entityId]; + + if (!state) { + continue; + } + + if (!state.attributes.unit_of_measurement) { + results.push(generateHistory(state, [state.state])); + continue; + } + + const numberState = Number(state.state); + + if (isNaN(numberState)) { + // tslint:disable-next-line + console.log( + "Ignoring state with unparsable state but with a unit", + entityId, + state + ); + continue; + } + + const statesToGenerate = 15; + let genFunc; + + if (incrementalUnits.includes(state.attributes.unit_of_measurement)) { + let initial = Math.floor( + numberState * 0.4 + numberState * Math.random() * 0.2 + ); + const diff = Math.max( + 1, + Math.floor((numberState - initial) / statesToGenerate) + ); + genFunc = () => { + initial += diff; + return Math.min(numberState, initial); + }; + } else { + const diff = Math.floor(numberState * (numberState > 80 ? 0.05 : 0.5)); + genFunc = () => + numberState - diff + Math.floor(Math.random() * 2 * diff); + } + + results.push( + generateHistory( + { + entity_id: state.entity_id, + attributes: state.attributes, + }, + Array.from({ length: statesToGenerate }, genFunc) + ) + ); + } + return results; + }); }; diff --git a/demo/src/stubs/system_log.ts b/demo/src/stubs/system_log.ts new file mode 100644 index 0000000000..a056d6ad79 --- /dev/null +++ b/demo/src/stubs/system_log.ts @@ -0,0 +1,5 @@ +import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; + +export const mockSystemLog = (hass: MockHomeAssistant) => { + hass.mockAPI("error/all", () => []); +}; diff --git a/demo/src/stubs/template.ts b/demo/src/stubs/template.ts new file mode 100644 index 0000000000..726926461c --- /dev/null +++ b/demo/src/stubs/template.ts @@ -0,0 +1,9 @@ +import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; + +export const mockTemplate = (hass: MockHomeAssistant) => { + hass.mockAPI("template", () => + Promise.reject({ + body: { message: "Template dev tool does not work in the demo." }, + }) + ); +}; diff --git a/src/fake_data/demo_config.ts b/src/fake_data/demo_config.ts index 2743032ec9..ef85b37244 100644 --- a/src/fake_data/demo_config.ts +++ b/src/fake_data/demo_config.ts @@ -11,7 +11,7 @@ export const demoConfig: HassConfig = { temperature: "°C", volume: "L", }, - components: ["conversation"], + components: ["conversation", "notify.html5", "history"], time_zone: "America/Los_Angeles", config_dir: "/config", version: "DEMO", diff --git a/src/fake_data/entity.ts b/src/fake_data/entity.ts index 5054fa0ae0..96c8919a64 100644 --- a/src/fake_data/entity.ts +++ b/src/fake_data/entity.ts @@ -66,7 +66,7 @@ export class Entity { } } -export class LightEntity extends Entity { +class LightEntity extends Entity { public async handleService(domain, service, data) { if (!["homeassistant", this.domain].includes(domain)) { return; @@ -89,7 +89,7 @@ export class LightEntity extends Entity { } } -export class SwitchEntity extends Entity { +class ToggleEntity extends Entity { public async handleService(domain, service, data) { if (!["homeassistant", this.domain].includes(domain)) { return; @@ -109,7 +109,7 @@ export class SwitchEntity extends Entity { } } -export class LockEntity extends Entity { +class LockEntity extends Entity { public async handleService( domain, service, @@ -128,7 +128,31 @@ export class LockEntity extends Entity { } } -export class CoverEntity extends Entity { +class AlarmControlPanelEntity extends Entity { + public async handleService( + domain, + service, + // @ts-ignore + data + ) { + if (domain !== this.domain) { + return; + } + + const serviceStateMap = { + alarm_arm_night: "armed_night", + alarm_arm_home: "armed_home", + alarm_arm_away: "armed_away", + alarm_disarm: "disarmed", + }; + + if (serviceStateMap[service]) { + this.update(serviceStateMap[service], this.baseAttributes); + } + } +} + +class CoverEntity extends Entity { public async handleService( domain, service, @@ -147,7 +171,7 @@ export class CoverEntity extends Entity { } } -export class ClimateEntity extends Entity { +class ClimateEntity extends Entity { public async handleService(domain, service, data) { if (domain !== this.domain) { return; @@ -162,7 +186,7 @@ export class ClimateEntity extends Entity { } } -export class GroupEntity extends Entity { +class GroupEntity extends Entity { public async handleService(domain, service, data) { if (!["homeassistant", this.domain].includes(domain)) { return; @@ -180,12 +204,14 @@ export class GroupEntity extends Entity { } const TYPES = { + alarm_control_panel: AlarmControlPanelEntity, climate: ClimateEntity, cover: CoverEntity, group: GroupEntity, + input_boolean: ToggleEntity, light: LightEntity, lock: LockEntity, - switch: SwitchEntity, + switch: ToggleEntity, }; export const getEntity = ( diff --git a/src/fake_data/provide_hass.ts b/src/fake_data/provide_hass.ts index 4bb724ee01..de409524af 100644 --- a/src/fake_data/provide_hass.ts +++ b/src/fake_data/provide_hass.ts @@ -13,7 +13,8 @@ import { translationMetadata } from "../resources/translations-metadata"; const ensureArray = (val: T | T[]): T[] => Array.isArray(val) ? val : [val]; -type RestCallback = ( +type MockRestCallback = ( + hass: MockHomeAssistant, method: string, path: string, parameters: { [key: string]: any } | undefined @@ -25,7 +26,7 @@ export interface MockHomeAssistant extends HomeAssistant { updateStates(newStates: HassEntities); addEntities(entites: Entity | Entity[], replace?: boolean); mockWS(type: string, callback: (msg: any) => any); - mockAPI(path: string | RegExp, callback: RestCallback); + mockAPI(path: string | RegExp, callback: MockRestCallback); mockEvent(event); mockTheme(theme: { [key: string]: string } | null); } @@ -39,7 +40,7 @@ export const provideHass = ( const hass = (): MockHomeAssistant => elements[0].hass; const wsCommands = {}; - const restResponses: Array<[string | RegExp, RestCallback]> = []; + const restResponses: Array<[string | RegExp, MockRestCallback]> = []; const eventListeners: { [event: string]: Array<(event) => void>; } = {}; @@ -160,7 +161,7 @@ export const provideHass = ( ); return response - ? response[1](method, path, parameters) + ? response[1](hass(), method, path, parameters) : Promise.reject(`API Mock for ${path} is not implemented`); }, fetchWithAuth: () => Promise.reject("Not implemented"), diff --git a/src/panels/dev-template/ha-panel-dev-template.js b/src/panels/dev-template/ha-panel-dev-template.js index 61a07919ab..f493f2b19e 100644 --- a/src/panels/dev-template/ha-panel-dev-template.js +++ b/src/panels/dev-template/ha-panel-dev-template.js @@ -210,7 +210,9 @@ For loop example: this.rendering = false; }.bind(this), function(error) { - this.processed = error.body.message; + this.processed = + (error && error.body && error.body.message) || + "Unknown error rendering template"; this.error = true; this.rendering = false; }.bind(this)