From 9a6fc6e810bd43e30c9e8b9e25952bff7e1254f7 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Thu, 16 Jul 2026 14:14:13 -0400 Subject: [PATCH] server: dispatch python plugin events to systemManager listeners (#2086) The python port of plugin-remote's notify() updates systemState but the dispatch to systemManager.events was left as a commented-out TODO, so systemManager.listen() callbacks never fire in python plugins/clients (plugin-remote.ts dispatches via notifyEventDetails here). Port the current typescript semantics: plain property changes update state and notify listeners with the unwrapped value, everything else passes through raw, and mixin property events no longer write device state. Also fix EventRegistry.listenDevice to register callbacks in the token-keyed listener set (it raised KeyError on the device id key, diverging from event-registry.ts) so watch-mode device listeners work. Co-authored-by: Claude Fable 5 --- server/python/plugin_remote.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/server/python/plugin_remote.py b/server/python/plugin_remote.py index a0981ceb1..98a32c6aa 100644 --- a/server/python/plugin_remote.py +++ b/server/python/plugin_remote.py @@ -159,8 +159,8 @@ class EventRegistry(object): events = set() self.listeners[token] = events callback = ensure_not_coroutine(callback) - self.listeners[id].add(callback) - return EventListenerRegisterImpl(lambda: self.listeners[id].remove(callback)) + events.add(callback) + return EventListenerRegisterImpl(lambda: events.discard(callback)) def notify( self, @@ -649,6 +649,7 @@ class PluginRemote: ): self.systemState: Mapping[str, Mapping[str, SystemDeviceState]] = {} self.nativeIds: Mapping[str, DeviceStorage] = {} + self.systemManager: SystemManager = None self.mediaManager: MediaManager self.clusterManager: ClusterManager self.consoles: Mapping[str, Future[Tuple[StreamReader, StreamWriter]]] = {} @@ -1113,18 +1114,18 @@ class PluginRemote: async def notify(self, id, eventDetails: EventDetails, value): property = eventDetails.get("property") - if property: - state = None - if self.systemState: - state = self.systemState.get(id, None) - if not state: - print("state not found for %s" % id) - return - state[property] = value - # systemManager.events.notify(id, eventTime, eventInterface, property, value.value, changed); - else: - # systemManager.events.notify(id, eventTime, eventInterface, property, value, changed); - pass + if property and not eventDetails.get("mixinId"): + state = self.systemState.get(id, None) if self.systemState else None + if not state: + print("state not found for %s" % id) + return + state[property] = value + if self.systemManager: + self.systemManager.events.notifyEventDetails( + id, eventDetails, value.get("value", None) if value else None + ) + elif self.systemManager: + self.systemManager.events.notifyEventDetails(id, eventDetails, value) async def ioEvent(self, id, event, message=None): pass