diff --git a/static/fluent/en-CA/main.ftl b/static/fluent/en-CA/main.ftl index 978eeed9c..a2c61bb8e 100644 --- a/static/fluent/en-CA/main.ftl +++ b/static/fluent/en-CA/main.ftl @@ -270,6 +270,7 @@ SmartPlug = Smart Plug Light = Light DoorSensor = Door Sensor MotionSensor = Motion Sensor +OccupancySensor = Occupancy Sensor LeakSensor = Leak Sensor PushButton = Push Button VideoCamera = Video Camera @@ -306,6 +307,8 @@ color-temperature = Colour Temperature video-unsupported = Sorry, video is not supported in your browser. motion = Motion no-motion = No Motion +occupied = Occupied +unoccupied = Unoccupied open = Open closed = Closed locked = Locked diff --git a/static/fluent/en-GB/main.ftl b/static/fluent/en-GB/main.ftl index ac4136c58..f0a1bf430 100644 --- a/static/fluent/en-GB/main.ftl +++ b/static/fluent/en-GB/main.ftl @@ -270,6 +270,7 @@ SmartPlug = Smart Plug Light = Light DoorSensor = Door Sensor MotionSensor = Motion Sensor +OccupancySensor = Occupancy Sensor LeakSensor = Leak Sensor PushButton = Push Button VideoCamera = Video Camera @@ -306,6 +307,8 @@ color-temperature = Colour Temperature video-unsupported = Sorry, video is not supported in your browser. motion = Motion no-motion = No Motion +occupied = Occupied +unoccupied = Unoccupied open = Open closed = Closed locked = Locked diff --git a/static/fluent/en-US/main.ftl b/static/fluent/en-US/main.ftl index daa3944a3..697d96f7c 100644 --- a/static/fluent/en-US/main.ftl +++ b/static/fluent/en-US/main.ftl @@ -271,6 +271,7 @@ SmartPlug = Smart Plug Light = Light DoorSensor = Door Sensor MotionSensor = Motion Sensor +OccupancySensor = Occupancy Sensor LeakSensor = Leak Sensor PushButton = Push Button VideoCamera = Video Camera @@ -307,6 +308,8 @@ color-temperature = Color Temperature video-unsupported = Sorry, video is not supported in your browser. motion = Motion no-motion = No Motion +occupied = Occupied +unoccupied = Unoccupied open = Open closed = Closed locked = Locked diff --git a/static/images/component-icons/occupancy-sensor-occupied.svg b/static/images/component-icons/occupancy-sensor-occupied.svg new file mode 100644 index 000000000..6b08a5e05 --- /dev/null +++ b/static/images/component-icons/occupancy-sensor-occupied.svg @@ -0,0 +1,37 @@ + + + + diff --git a/static/images/component-icons/occupancy-sensor-unoccupied.svg b/static/images/component-icons/occupancy-sensor-unoccupied.svg new file mode 100644 index 000000000..b48af1066 --- /dev/null +++ b/static/images/component-icons/occupancy-sensor-unoccupied.svg @@ -0,0 +1,33 @@ + + + + diff --git a/static/images/thing-icons/occupancy_sensor.svg b/static/images/thing-icons/occupancy_sensor.svg new file mode 100644 index 000000000..001be2a3f --- /dev/null +++ b/static/images/thing-icons/occupancy_sensor.svg @@ -0,0 +1,34 @@ + + + + diff --git a/static/js/app.js b/static/js/app.js index d2bbbf909..666710fa8 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -518,6 +518,7 @@ require('./components/capability/lock'); require('./components/capability/motion-sensor'); require('./components/capability/multi-level-sensor'); require('./components/capability/multi-level-switch'); +require('./components/capability/occupancy-sensor'); require('./components/capability/on-off-switch'); require('./components/capability/push-button'); require('./components/capability/smart-plug'); @@ -546,6 +547,7 @@ require('./components/property/locked'); require('./components/property/motion'); require('./components/property/number'); require('./components/property/numeric-label'); +require('./components/property/occupied'); require('./components/property/on-off'); require('./components/property/open'); require('./components/property/pushed'); diff --git a/static/js/components/capability/occupancy-sensor.js b/static/js/components/capability/occupancy-sensor.js new file mode 100644 index 000000000..377dd20c7 --- /dev/null +++ b/static/js/components/capability/occupancy-sensor.js @@ -0,0 +1,98 @@ +/** + * OccupancySensorCapability + * + * A bubble showing an occupancy sensor icon. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +'use strict'; + +const BaseComponent = require('../base-component'); +const fluent = require('../../fluent'); + +const template = document.createElement('template'); +template.innerHTML = ` + +
+`; + +class OccupancySensorCapability extends BaseComponent { + constructor() { + super(template); + + this._icon = this.shadowRoot.querySelector('#icon'); + this._label = this.shadowRoot.querySelector('#label'); + + this._occupied = false; + } + + connectedCallback() { + this.occupied = typeof this.dataset.occupied !== 'undefined' ? this.dataset.occupied : null; + } + + get occupied() { + return this._occupied; + } + + set occupied(value) { + this._occupied = Boolean(value); + + if (value === null) { + this._icon.classList.remove('occupied'); + this._label.innerText = fluent.getMessage('ellipsis'); + } else if (this._occupied) { + this._icon.classList.add('occupied'); + this._label.innerText = fluent.getMessage('occupied'); + } else { + this._icon.classList.remove('occupied'); + this._label.innerText = fluent.getMessage('unoccupied'); + } + } +} + +window.customElements.define('webthing-occupancy-sensor-capability', OccupancySensorCapability); +module.exports = OccupancySensorCapability; diff --git a/static/js/components/property/occupied.js b/static/js/components/property/occupied.js new file mode 100644 index 000000000..72a968cc0 --- /dev/null +++ b/static/js/components/property/occupied.js @@ -0,0 +1,22 @@ +/** + * OccupiedProperty + * + * A bubble showing an occupied or not occupied label. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +'use strict'; + +const StringLabelProperty = require('./string-label'); + +class OccupiedProperty extends StringLabelProperty { + connectedCallback() { + this.uppercase = true; + super.connectedCallback(); + } +} + +window.customElements.define('webthing-occupied-property', OccupiedProperty); +module.exports = OccupiedProperty; diff --git a/static/js/icons.js b/static/js/icons.js index f7d6ecf8d..c1e896b71 100644 --- a/static/js/icons.js +++ b/static/js/icons.js @@ -46,6 +46,8 @@ function capabilityToIcon(capability) { return '/images/thing-icons/door_sensor.svg'; case 'MotionSensor': return '/images/thing-icons/motion_sensor.svg'; + case 'OccupancySensor': + return '/images/thing-icons/occupancy_sensor.svg'; case 'LeakSensor': return '/images/thing-icons/leak_sensor.svg'; case 'SmokeSensor': diff --git a/static/js/logs/log.js b/static/js/logs/log.js index 7401c05c2..516cfbfa0 100644 --- a/static/js/logs/log.js +++ b/static/js/logs/log.js @@ -863,6 +863,8 @@ class Log { return value ? fluent.getMessage('on') : fluent.getMessage('off'); case 'MotionProperty': return value ? fluent.getMessage('motion') : fluent.getMessage('no-motion'); + case 'OccupiedProperty': + return value ? fluent.getMessage('occupied') : fluent.getMessage('unoccupied'); case 'OpenProperty': return value ? fluent.getMessage('open') : fluent.getMessage('closed'); case 'LeakProperty': diff --git a/static/js/schema-impl/capability/capabilities.js b/static/js/schema-impl/capability/capabilities.js index 4b266cbf8..5e0af989d 100644 --- a/static/js/schema-impl/capability/capabilities.js +++ b/static/js/schema-impl/capability/capabilities.js @@ -22,6 +22,7 @@ const Lock = require('./lock'); const MotionSensor = require('./motion-sensor'); const MultiLevelSensor = require('./multi-level-sensor'); const MultiLevelSwitch = require('./multi-level-switch'); +const OccupancySensor = require('./occupancy-sensor'); const OnOffSwitch = require('./on-off-switch'); const PushButton = require('./push-button'); const SmartPlug = require('./smart-plug'); @@ -56,6 +57,8 @@ function createThingFromCapability(capability, thingModel, description, format) return new DoorSensor(thingModel, description, format); case 'MotionSensor': return new MotionSensor(thingModel, description, format); + case 'OccupancySensor': + return new OccupancySensor(thingModel, description, format); case 'LeakSensor': return new LeakSensor(thingModel, description, format); case 'SmokeSensor': @@ -110,6 +113,8 @@ function getClassFromCapability(capability) { return 'door-sensor'; case 'MotionSensor': return 'motion-sensor'; + case 'OccupancySensor': + return 'occupancy-sensor'; case 'LeakSensor': return 'leak-sensor'; case 'SmokeSensor': diff --git a/static/js/schema-impl/capability/occupancy-sensor.js b/static/js/schema-impl/capability/occupancy-sensor.js new file mode 100644 index 000000000..83b35e8a4 --- /dev/null +++ b/static/js/schema-impl/capability/occupancy-sensor.js @@ -0,0 +1,78 @@ +/** + * Occupancy Sensor. + * + * UI element representing an Occupancy Sensor. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +'use strict'; + +const Thing = require('./thing'); + +class OccupancySensor extends Thing { + /** + * OccupancySensor Constructor (extends Thing). + * + * @param {Object} description Thing description object. + * @param {Number} format See Constants.ThingFormat + */ + constructor(model, description, format) { + super(model, description, format, { + baseIcon: '/images/thing-icons/occupancy_sensor.svg', + }); + } + + /** + * Find any properties required for this view. + */ + findProperties() { + this.occupiedProperty = null; + + // Look for properties by type first. + for (const name in this.displayedProperties) { + const type = this.displayedProperties[name].property['@type']; + + if (type === 'OccupiedProperty') { + this.occupiedProperty = name; + break; + } + } + + // If necessary, match on name. + if (this.occupiedProperty === null && this.displayedProperties.occupied) { + this.occupiedProperty = 'occupied'; + } + } + + get icon() { + return this.element.querySelector('webthing-occupancy-sensor-capability'); + } + + /** + * Update the display for the provided property. + * @param {string} name - name of the property + * @param {*} value - value of the property + */ + updateProperty(name, value) { + value = super.updateProperty(name, value); + + if (!this.displayedProperties.hasOwnProperty(name)) { + return; + } + + if (name === this.occupiedProperty) { + this.icon.occupied = !!value; + } + } + + iconView() { + return ` +