Changeset - 2b8a2a25b154
[Not reviewed]
default
0 3 0
drewp@bigasterisk.com - 20 months ago 2023-05-28 00:56:28
drewp@bigasterisk.com
logging
3 files changed with 5 insertions and 4 deletions:
0 comments (0 inline, 0 general)
light9/collector/collector.py
Show inline comments
 
@@ -8,92 +8,93 @@ from rdflib import URIRef
 

	
 
from light9.collector.device import resolve, toOutputAttrs
 
from light9.collector.output import Output as OutputInstance
 
from light9.collector.weblisteners import WebListeners
 
from light9.effect.settings import DeviceSettings
 
from light9.namespaces import L9, RDF
 
from light9.newtypes import (ClientSessionType, ClientType, DeviceAttr, DeviceClass, DeviceSetting, DeviceUri, DmxIndex, DmxMessageIndex, OutputAttr,
 
                             OutputRange, OutputUri, OutputValue, UnixTime, VTUnion, uriTail)
 

	
 
log = logging.getLogger('collector')
 

	
 

	
 
def makeDmxMessageIndex(base: DmxIndex, offset: DmxIndex) -> DmxMessageIndex:
 
    return DmxMessageIndex(base + offset - 1)
 

	
 

	
 
def _outputMap(graph: SyncedGraph, outputs: Set[OutputUri]) -> Dict[Tuple[DeviceUri, OutputAttr], Tuple[OutputUri, DmxMessageIndex]]:
 
    """From rdf config graph, compute a map of
 
       (device, outputattr) : (output, index)
 
    that explains which output index to set for any device update.
 
    """
 
    ret = cast(Dict[Tuple[DeviceUri, OutputAttr], Tuple[OutputUri, DmxMessageIndex]], {})
 

	
 
    for dc in graph.subjects(RDF.type, L9['DeviceClass']):
 
        log.info('mapping devices of class %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)
 
            log.info('    💡 mapping device %s', dev)
 
            universe = typedValue(OutputUri, graph, dev, L9['dmxUniverse'])
 
            if universe not in outputs:
 
                raise ValueError(f'{dev=} is configured to be in {universe=}, but we have no Output for that universe')
 
            try:
 
                dmxBase = typedValue(DmxIndex, graph, dev, L9['dmxBase'])
 
            except ValueError:
 
                raise ValueError('no :dmxBase for %s' % dev)
 

	
 
            for row in sorted(graph.objects(dc, L9['attr']), key=str):
 
                outputAttr = typedValue(OutputAttr, graph, row, L9['outputAttr'])
 
                offset = typedValue(DmxIndex, graph, row, L9['dmxOffset'])
 
                index = makeDmxMessageIndex(dmxBase, offset)
 
                ret[(dev, outputAttr)] = (universe, index)
 
                log.info(f'      {uriTail(outputAttr):15} maps to {uriTail(universe)} index {index}')
 
    return ret
 

	
 

	
 
class Collector:
 
    """receives setAttrs calls; combines settings; renders them into what outputs like; calls Output.update"""
 

	
 
    def __init__(self, graph: SyncedGraph, outputs: List[OutputInstance], listeners: WebListeners, clientTimeoutSec: float = 10):
 
        self.graph = graph
 
        self.outputs = outputs
 
        self.listeners = listeners
 
        self.clientTimeoutSec = clientTimeoutSec
 

	
 
        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._compile)
 

	
 
        # rename to activeSessons ?
 
        self.lastRequest: Dict[Tuple[ClientType, ClientSessionType], Tuple[UnixTime, Dict[Tuple[DeviceUri, DeviceAttr], VTUnion]]] = {}
 

	
 
        # (dev, devAttr): value to use instead of 0
 
        self.stickyAttrs: Dict[Tuple[DeviceUri, DeviceAttr], VTUnion] = {}
 

	
 
    def _compile(self):
 
        log.info('Collector._compile:')
 
        self._outputByUri = self._compileOutputByUri()
 
        self._outputMap = _outputMap(self.graph, set(self._outputByUri.keys()))
 

	
 
        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._deviceType[dev] = dc
 
                self._compileRemapForDevice(dev)
 

	
 
    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))
light9/live/Light9AttrControl.ts
Show inline comments
 
@@ -116,49 +116,49 @@ export class Light9AttrControl extends L
 
    if (this.deviceAttrRow === null) throw new Error();
 
    if (this.effect === null) throw new Error();
 
    // log("graph->ui on ", this.deviceAttrRow.device, this.deviceAttrRow.uri);
 
    const v = this.effect.currentValue(this.deviceAttrRow.device, this.deviceAttrRow.uri);
 
    this.onGraphValueChanged(v);
 
  }
 

	
 
  private onDeviceAttrRowProperty() {
 
    if (this.deviceAttrRow === null) throw new Error();
 
    const d = this.deviceAttrRow.dataType;
 
    if (d.equals(makeType("scalar"))) {
 
      this.dataType = "scalar";
 
    } else if (d.equals(makeType("color"))) {
 
      this.dataType = "color";
 
    } else if (d.equals(makeType("choice"))) {
 
      this.dataType = "choice";
 
    }
 
  }
 

	
 
  onValueInput(ev: CustomEvent) {
 
    if (ev.detail === undefined) {
 
      // not sure what this is, but it seems to be followed by good events
 
      return;
 
    }
 
    log(ev.type, ev.detail.value);
 
    // log(ev.type, ev.detail.value);
 
    this.value = ev.detail.value;
 
    // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, ev.detail.value);
 
  }
 

	
 
  onGraphValueChanged(v: ControlValue | null) {
 
    if (this.deviceAttrRow === null) throw new Error();
 
    // log("change: control must display", v, "for", this.deviceAttrRow.device.value, this.deviceAttrRow.uri.value);
 
    // this.enableChange = false;
 
    if (this.dataType == "scalar") {
 
      if (v !== null) {
 
        this.value = v;
 
      } else {
 
        this.value = 0;
 
      }
 
    } else if (this.dataType == "color") {
 
      this.value = v;
 
    }
 
  }
 

	
 
  goBlack() {
 
    this.value = "#000000";
 
  }
 

	
 
  onChoice(value: any) {
light9/rdfdb/service.py
Show inline comments
 
import logging
 
import os
 
from pathlib import Path
 

	
 
from light9.run_local import log
 

	
 
import rdfdb.service
 
from rdflib import URIRef
 

	
 
from light9 import showconfig
 
logging.getLogger('rdfdb').setLevel(logging.INFO)
 
logging.getLogger('rdfdb.file').setLevel(logging.INFO)
 
logging.getLogger('rdfdb.graph').setLevel(logging.INFO)
 
logging.getLogger('rdfdb.net').setLevel(logging.DEBUG)
 
logging.getLogger('rdfdb.net').setLevel(logging.INFO)
 
rdfRoot = Path(os.environ['LIGHT9_SHOW'].rstrip('/') + '/')
 
showUri = URIRef(showconfig.showUri() + '/')
 

	
 
app = rdfdb.service.makeApp(  #
 
    dirUriMap={rdfRoot: showUri},
 
    prefixes={
 
        'show': showUri,
 
        '': URIRef('http://light9.bigasterisk.com/'),
 
        'rdf': URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#'),
 
        'rdfs': URIRef('http://www.w3.org/2000/01/rdf-schema#'),
 
        'xsd': URIRef('http://www.w3.org/2001/XMLSchema#'),
 
        'effect': URIRef('http://light9.bigasterisk.com/effect/'),
 
        'dev': URIRef('http://light9.bigasterisk.com/theater/skyline/device/'),
 
    })
0 comments (0 inline, 0 general)