diff --git a/light9/collector/collector.py b/light9/collector/collector.py --- a/light9/collector/collector.py +++ b/light9/collector/collector.py @@ -35,7 +35,7 @@ def _outputMap(graph: SyncedGraph, outpu ret = cast(Dict[Tuple[DeviceUri, OutputAttr], Tuple[OutputUri, DmxMessageIndex]], {}) for dc in graph.subjects(RDF.type, L9['DeviceClass']): - log.info('mapping DeviceClass %s', dc) + log.info('mapping devices of class %s', dc) for dev in graph.subjects(RDF.type, dc): dev = cast(DeviceUri, dev) log.info(' 💡 mapping device %s', dev) @@ -64,11 +64,13 @@ class Collector: self.outputs = outputs self.listeners = listeners self.clientTimeoutSec = clientTimeoutSec - self.initTime = time.time() - self.allDevices: Set[DeviceUri] = set() + + self._initTime = time.time() self._outputByUri: Dict[OutputUri, OutputInstance] = {} + self._deviceType: Dict[DeviceUri, DeviceClass] = {} + self.remapOut: Dict[Tuple[DeviceUri, OutputAttr], OutputRange] = {} - self.graph.addHandler(self._rebuildOutputMap) + self.graph.addHandler(self._compile) # rename to activeSessons ? self.lastRequest: Dict[Tuple[ClientType, ClientSessionType], Tuple[UnixTime, Dict[Tuple[DeviceUri, DeviceAttr], VTUnion]]] = {} @@ -76,28 +78,31 @@ class Collector: # (dev, devAttr): value to use instead of 0 self.stickyAttrs: Dict[Tuple[DeviceUri, DeviceAttr], VTUnion] = {} - def _rebuildOutputMap(self): - self.allDevices.clear() + def _compile(self): + self._outputByUri = self._compileOutputByUri() + self._outputMap = _outputMap(self.graph, set(self._outputByUri.keys())) - self._outputByUri.clear() - for out in self.outputs: - self._outputByUri[OutputUri(out.uri)] = out - - self.outputMap = _outputMap(self.graph, set(self._outputByUri.keys())) - self.deviceType: Dict[DeviceUri, DeviceClass] = {} - self.remapOut: Dict[Tuple[DeviceUri, OutputAttr], OutputRange] = {} + self._deviceType.clear() + self.remapOut.clear() for dc in self.graph.subjects(RDF.type, L9['DeviceClass']): dc = cast(DeviceClass, dc) for dev in self.graph.subjects(RDF.type, dc): dev = cast(DeviceUri, dev) - self.allDevices.add(dev) - self.deviceType[dev] = dc + self._deviceType[dev] = dc + self._compileRemapForDevice(dev) - for remap in self.graph.objects(dev, L9['outputAttrRange']): - attr = typedValue(OutputAttr, self.graph, remap, L9['outputAttr']) - start = typedValue(float, self.graph, remap, L9['start']) - end = typedValue(float, self.graph, remap, L9['end']) - self.remapOut[(dev, attr)] = OutputRange((start, end)) + def _compileOutputByUri(self) -> Dict[OutputUri, OutputInstance]: + ret = {} + for output in self.outputs: + ret[OutputUri(output.uri)] = output + return ret + + def _compileRemapForDevice(self, dev: DeviceUri): + for remap in self.graph.objects(dev, L9['outputAttrRange']): + attr = typedValue(OutputAttr, self.graph, remap, L9['outputAttr']) + start = typedValue(float, self.graph, remap, L9['start']) + end = typedValue(float, self.graph, remap, L9['end']) + self.remapOut[(dev, attr)] = OutputRange((start, end)) def _forgetStaleClients(self, now): staleClientSessions = [] @@ -114,14 +119,14 @@ class Collector: for devUri, devAttr, val in settingsList: if (devUri, devAttr) in out: existingVal = out[(devUri, devAttr)] - out[(devUri, devAttr)] = resolve(self.deviceType[devUri], devAttr, [existingVal, val]) + out[(devUri, devAttr)] = resolve(self._deviceType[devUri], devAttr, [existingVal, val]) else: out[(devUri, devAttr)] = val return out def _warnOnLateRequests(self, client, now, sendTime): requestLag = now - sendTime - if requestLag > .1 and now > self.initTime + 10 and getattr(self, '_lastWarnTime', 0) < now - 3: + if requestLag > .1 and now > self._initTime + 10 and getattr(self, '_lastWarnTime', 0) < now - 3: self._lastWarnTime = now log.warn('collector.setAttrs from %s is running %.1fms after the request was made', client, requestLag * 1000) @@ -176,15 +181,10 @@ class Collector: deviceAttrs = self._merge(iter(self.lastRequest.values())) outputAttrs = cast(Dict[DeviceUri, Dict[OutputAttr, OutputValue]], {}) - for d in self.allDevices: - try: - devType = self.deviceType[d] - except KeyError: - log.warn("request for output to unconfigured device %s" % d) - continue + for d, devType in self._deviceType.items(): try: outputAttrs[d] = toOutputAttrs(devType, deviceAttrs.get(d, {})) - self.listeners.outputAttrsSet(d, outputAttrs[d], self.outputMap) + self.listeners.outputAttrsSet(d, outputAttrs[d], self._outputMap) except Exception as e: log.error('failing toOutputAttrs on %s: %r', d, e) @@ -209,7 +209,7 @@ class Collector: for device, attrs in outputAttrs.items(): for outputAttr, value in attrs.items(): - outputUri, _index = self.outputMap[(device, outputAttr)] + outputUri, _index = self._outputMap[(device, outputAttr)] index = DmxMessageIndex(_index) outArray = pendingOut[outputUri] if outArray[index] != 0: