diff --git a/custom_components/browser_mod/binary_sensor.py b/custom_components/browser_mod/binary_sensor.py index b0d2fd0..544be5b 100644 --- a/custom_components/browser_mod/binary_sensor.py +++ b/custom_components/browser_mod/binary_sensor.py @@ -16,7 +16,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class BrowserBinarySensor(BrowserModEntity, BinarySensorEntity): def __init__(self, coordinator, browserID, parameter, name): - super().__init__(coordinator, browserID, name) + BrowserModEntity.__init__(self, coordinator, browserID, name) + BinarySensorEntity.__init__(self) self.parameter = parameter @property @@ -25,3 +26,27 @@ class BrowserBinarySensor(BrowserModEntity, BinarySensorEntity): data = data.get("browser", {}) data = data.get(self.parameter, None) return data + + +class ActivityBinarySensor(BrowserModEntity, BinarySensorEntity): + def __init__(self, coordinator, browserID): + BrowserModEntity.__init__(self, coordinator, browserID, None) + BinarySensorEntity.__init__(self) + + @property + def unique_id(self): + return f"{self.browserID}-activity" + + @property + def entity_registry_visible_default(self): + return True + + @property + def device_class(self): + return "motion" + + @property + def is_on(self): + data = self._data + data = data.get("activity", False) + return data diff --git a/custom_components/browser_mod/browser.py b/custom_components/browser_mod/browser.py index abba9e1..b3971aa 100644 --- a/custom_components/browser_mod/browser.py +++ b/custom_components/browser_mod/browser.py @@ -7,7 +7,7 @@ from .const import DATA_BROWSERS, DOMAIN, DATA_ADDERS from .coordinator import Coordinator from .sensor import BrowserSensor from .light import BrowserModLight -from .binary_sensor import BrowserBinarySensor +from .binary_sensor import BrowserBinarySensor, ActivityBinarySensor from .media_player import BrowserModPlayer from .camera import BrowserModCamera @@ -68,6 +68,12 @@ class BrowserModBrowser: if self.data.get("browser", {}).get("charging", None) is not None: _assert_browser_sensor("binary_sensor", "charging", "Browser charging") + if "activity" not in self.entities: + adder = hass.data[DOMAIN][DATA_ADDERS]["binary_sensor"] + new = ActivityBinarySensor(coordinator, browserID) + adder([new]) + self.entities["activity"] = new + if "screen" not in self.entities: adder = hass.data[DOMAIN][DATA_ADDERS]["light"] new = BrowserModLight(coordinator, browserID, self) diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index fa510cb..e9d9224 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -909,6 +909,41 @@ const ServicesMixin = (SuperClass) => { }; }; +const ActivityMixin = (SuperClass) => { + return class ActivityMixinClass extends SuperClass { + constructor() { + super(); + this.activityTriggered = false; + this._activityCooldown = 15000; + for (const ev of ["pointerdown", "pointermove", "keydown"]) { + window.addEventListener(ev, () => this.activityTrigger()); + } + this.addEventListener("fully-update", () => { + this.activityTrigger(); + }); + } + activityTrigger() { + if (!this.activityTriggered) { + this.sendUpdate({ + activity: true, + }); + } + this.activityTriggered = true; + clearTimeout(this._activityTimeout); + this._activityTimeout = setTimeout(() => this.activityReset(), this._activityCooldown); + } + activityReset() { + clearTimeout(this._activityTimeout); + if (this.activityTriggered) { + this.sendUpdate({ + activity: false, + }); + } + this.activityTriggered = false; + } + }; +}; + /** * @license * Copyright 2017 Google LLC @@ -1301,7 +1336,7 @@ var pjson = { - Media_seek - Screensavers */ -class BrowserMod extends ServicesMixin(PopupMixin(BrowserStateMixin(CameraMixin(MediaPlayerMixin(ScreenSaverMixin(FullyMixin(RequireInteractMixin(ConnectionMixin(EventTarget))))))))) { +class BrowserMod extends ServicesMixin(PopupMixin(ActivityMixin(BrowserStateMixin(CameraMixin(MediaPlayerMixin(ScreenSaverMixin(FullyMixin(RequireInteractMixin(ConnectionMixin(EventTarget)))))))))) { constructor() { super(); this.connect(); diff --git a/custom_components/browser_mod/sensor.py b/custom_components/browser_mod/sensor.py index f64ed2c..7b89d02 100644 --- a/custom_components/browser_mod/sensor.py +++ b/custom_components/browser_mod/sensor.py @@ -24,7 +24,8 @@ class BrowserSensor(BrowserModEntity, SensorEntity): unit_of_measurement=None, device_class=None, ): - super().__init__(coordinator, browserID, name) + BrowserModEntity.__init__(self, coordinator, browserID, name) + SensorEntity.__init__(self) self.parameter = parameter self._device_class = device_class self._unit_of_measurement = unit_of_measurement diff --git a/js/plugin/activity.ts b/js/plugin/activity.ts new file mode 100644 index 0000000..ee6ebbf --- /dev/null +++ b/js/plugin/activity.ts @@ -0,0 +1,40 @@ +export const ActivityMixin = (SuperClass) => { + return class ActivityMixinClass extends SuperClass { + activityTriggered = false; + _activityCooldown = 15000; + _activityTimeout; + constructor() { + super(); + for (const ev of ["pointerdown", "pointermove", "keydown"]) { + window.addEventListener(ev, () => this.activityTrigger()); + } + this.addEventListener("fully-update", () => { + this.activityTrigger(); + }); + } + + activityTrigger() { + if (!this.activityTriggered) { + this.sendUpdate({ + activity: true, + }); + } + this.activityTriggered = true; + clearTimeout(this._activityTimeout); + this._activityTimeout = setTimeout( + () => this.activityReset(), + this._activityCooldown + ); + } + + activityReset() { + clearTimeout(this._activityTimeout); + if (this.activityTriggered) { + this.sendUpdate({ + activity: false, + }); + } + this.activityTriggered = false; + } + }; +}; diff --git a/js/plugin/main.ts b/js/plugin/main.ts index e4702b8..e42188f 100644 --- a/js/plugin/main.ts +++ b/js/plugin/main.ts @@ -9,6 +9,7 @@ import { RequireInteractMixin } from "./require-interact"; import { FullyMixin } from "./fullyKiosk"; import { BrowserStateMixin } from "./browser"; import { ServicesMixin } from "./services"; +import { ActivityMixin } from "./activity"; import "./popups"; import { PopupMixin } from "./popups"; import pjson from "../../package.json"; @@ -59,11 +60,13 @@ import pjson from "../../package.json"; */ export class BrowserMod extends ServicesMixin( PopupMixin( - BrowserStateMixin( - CameraMixin( - MediaPlayerMixin( - ScreenSaverMixin( - FullyMixin(RequireInteractMixin(ConnectionMixin(EventTarget))) + ActivityMixin( + BrowserStateMixin( + CameraMixin( + MediaPlayerMixin( + ScreenSaverMixin( + FullyMixin(RequireInteractMixin(ConnectionMixin(EventTarget))) + ) ) ) )