Changeset - 7a5c7721bf6d
[Not reviewed]
default
0 2 0
drewp@bigasterisk.com - 8 months ago 2024-05-20 01:31:53
drewp@bigasterisk.com
better collector err handling
2 files changed with 12 insertions and 4 deletions:
0 comments (0 inline, 0 general)
src/light9/collector/output.py
Show inline comments
 
@@ -183,25 +183,25 @@ class Udmx(BackgroundLoopOutput):
 
        super().__init__(uri, rate=rate)
 

	
 
        self.reconnect()
 

	
 
    def shortId(self) -> str:
 
        return super().shortId() + f'_bus={self.bus}'
 

	
 
    def reconnect(self):
 
        metrics('connected', output=self.shortId()).set(0)
 
        from pyudmx import pyudmx
 
        self.dev = pyudmx.uDMXDevice()
 
        if not self.dev.open(bus=self.bus, address=self.address):
 
            raise ValueError("dmx open failed")
 
            raise ValueError(f"dmx open(bus={self.bus}, address={self.address}) failed")
 
        log.info(f'opened {self.dev}')
 
        metrics('connected', output=self.shortId()).set(1)
 
        metrics('reconnections', output=self.shortId()).inc()
 

	
 
    #def update(self, buf:bytes):
 
    #    self._write(buf)
 

	
 
    #def _loop(self):
 
    #    pass
 
    def _write(self, buf):
 
        if not self.dev:
 
            log.info('%s: trying to connect', self.shortId())
 
@@ -243,24 +243,27 @@ class Udmx(BackgroundLoopOutput):
 
                    return
 

	
 
                msg = 'usb: sending %s bytes to %r; error %r' % (len(buf), self.uri, e)
 
                log.warn(msg)
 

	
 
                if e.errno == 13:  # permissions
 
                    return self.crash()
 

	
 
                if e.errno == 19:  # no such dev; usb hw restarted
 
                    self.reconnect()
 
                    return
 

	
 
                if e.errno == 110:  # USBTimeoutError
 
                    return self.crash()
 

	
 
                raise
 
            dt = time.time() - t1
 
            if dt > 1 / self.rate * 1.5:
 
                log.warning(f'usb stall- took {(dt*1000):.2f}ms')
 

	
 

	
 
'''
 
# the code used in 2018 and before
 
class UdmxOld(BackgroundLoopOutput):
 

	
 
    def __init__(self, uri, bus):
 
        from light9.io.udmx import Udmx
src/light9/collector/service.py
Show inline comments
 
#!bin/python
 
"""
 
Collector receives device attrs from multiple senders, combines
 
them, and sends output attrs to hardware. The combining part has
 
custom code for some attributes.
 

	
 
Input can be over http or zmq.
 
"""
 
import asyncio
 
import functools
 
import logging
 
import os
 
import stat
 
import subprocess
 
import traceback
 
from typing import List
 

	
 
from light9 import networking
 
from light9.collector.collector import Collector
 
from light9.collector.output import ArtnetDmx, DummyOutput, Output, Udmx  # noqa
 
from light9.collector.weblisteners import UiListener, WebListeners
 
from light9.namespaces import L9
 
from light9.run_local import log
 
from light9.zmqtransport import parseJsonMessage
 
from rdfdb.syncedgraph.syncedgraph import SyncedGraph
 
@@ -85,48 +87,51 @@ async def zmqListener(collector):
 
            collector.setAttrs(client, clientSession, settings, sendTime)
 
    except:
 
        traceback.print_exc()
 
        raise
 

	
 

	
 
def findDevice():
 
    for line in subprocess.check_output("lsusb").decode('utf8').splitlines():
 
        if '16c0:05dc' in line:
 
            words = line.split(':')[0].split()
 
            dev = f'/dev/bus/usb/{words[1]}/{words[3]}'
 
            log.info(f'device will be {dev}')
 
            return dev, int(words[3])
 
            st = os.stat(dev)
 
            if not (st.st_mode & (stat.S_IWUSR | stat.S_IRUSR)):
 
                raise ValueError(f'{dev} has insufficient stat ({stat.filemode(st.st_mode)})')
 
            return dev, int(words[1]), int(words[3])
 
    raise ValueError("no matching uDMX found")
 

	
 

	
 
def main():
 
    logging.getLogger('autodepgraphapi').setLevel(logging.INFO)
 
    logging.getLogger('syncedgraph').setLevel(logging.INFO)
 
    logging.getLogger('output.allDmx').setLevel(logging.WARNING)
 
    logging.getLogger().setLevel(logging.DEBUG)
 
    logging.getLogger('collector').setLevel(logging.DEBUG)
 

	
 
    graph = SyncedGraph(networking.rdfdb.url, "collector")
 

	
 
    devPath, usbAddress = findDevice()
 
    devPath, bus, usbAddress = findDevice()
 
    # if user doesn't have r/w, fail now
 
    try:
 
        # todo: drive outputs with config files
 
        outputs: List[Output] = [
 
            # ArtnetDmx(L9['output/dmxA/'],
 
            #           host='127.0.0.1',
 
            #           port=6445,
 
            #           rate=rate),
 
            #sudo chmod a+rw /dev/bus/usb/003/021
 
            Udmx(L9['output/dmxA/'], bus=3, address=usbAddress, lastDmxChannel=200, rate=RATE),
 
            Udmx(L9['output/dmxA/'], bus=bus, address=usbAddress, lastDmxChannel=200, rate=RATE),
 
        ]
 
    except Exception:
 
        log.error("setting up outputs:")
 
        traceback.print_exc()
 
        raise
 
    listeners = WebListeners()
 
    c = Collector(graph, outputs, listeners)
 
    zl = asyncio.create_task(zmqListener(c))
 
    app = Starlette(
 
        debug=True,
 
        routes=[
 
            # Route('/recentRequests', lambda req: get_recentRequests(req, db)),
0 comments (0 inline, 0 general)