# HG changeset patch # User drewp@bigasterisk.com # Date 2023-05-20 00:28:03 # Node ID 081f36506ad3067d9a7ebba71aeccadfccacfb68 # Parent 5db8e7698d6a0c51ec5f443a720833ebb6b1b4ef address a bunch of type errors and loose types diff --git a/light9/ascoltami/musictime_client.py b/light9/ascoltami/musictime_client.py --- a/light9/ascoltami/musictime_client.py +++ b/light9/ascoltami/musictime_client.py @@ -77,11 +77,11 @@ class MusicTime(object): self.position = position self.onChange(position) - cast(IReactorTime, reactor).callLater(self.period, self.pollMusicTime) + cast(IReactorTime, reactor).callLater(self.period, self.pollMusicTime) # type: ignore def eb(err): log.warn("talking to ascoltami: %s", err.getErrorMessage()) - cast(IReactorTime, reactor).callLater(2, self.pollMusicTime) + cast(IReactorTime, reactor).callLater(2, self.pollMusicTime) # type: ignore d = treq.get(networking.musicPlayer.path("time").toPython()) d.addCallback(cb) diff --git a/light9/ascoltami/webapp.py b/light9/ascoltami/webapp.py --- a/light9/ascoltami/webapp.py +++ b/light9/ascoltami/webapp.py @@ -111,12 +111,12 @@ class timeStreamResource(cyclone.websock now = time.time() msg = currentState(self.settings.app.graph, self.settings.app.player) if msg != self.lastSent or now > self.lastSentTime + 2: - self.sendMessage(json.dumps(msg)) + # self.sendMessage(json.dumps(msg)) self.lastSent = msg self.lastSentTime = now if self.transport.connected: - cast(IReactorTime, reactor).callLater(.2, self.loop) + cast(IReactorTime, reactor).callLater(.2, self.loop) # type: ignore def connectionLost(self, reason): log.info("bye ws client %r: %s", self, reason) diff --git a/light9/collector/collector.py b/light9/collector/collector.py --- a/light9/collector/collector.py +++ b/light9/collector/collector.py @@ -102,11 +102,12 @@ class Collector: # todo: move to settings.py def resolvedSettingsDict(self, settingsList: List[DeviceSetting]) -> Dict[Tuple[DeviceUri, DeviceAttr], VTUnion]: out: Dict[Tuple[DeviceUri, DeviceAttr], VTUnion] = {} - for d, da, v in settingsList: - if (d, da) in out: - out[(d, da)] = resolve(d, da, [out[(d, da)], v]) + 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]) else: - out[(d, da)] = v + out[(devUri, devAttr)] = val return out def _warnOnLateRequests(self, client, now, sendTime): @@ -154,8 +155,8 @@ class Collector: clientTimeoutSec. """ # todo: cleanup session code if we really don't want to be able to run multiple sessions of one client - clientSession = ClientSessionType("no_longer_used") - + clientSession = ClientSessionType("no_longer_used") + now = UnixTime(time.time()) self._warnOnLateRequests(client, now, sendTime) diff --git a/light9/collector/device.py b/light9/collector/device.py --- a/light9/collector/device.py +++ b/light9/collector/device.py @@ -5,7 +5,7 @@ from rdflib import Literal, URIRef from webcolors import hex_to_rgb, rgb_to_hex from colormath.color_objects import sRGBColor, CMYColor import colormath.color_conversions -from light9.newtypes import VT, HexColor, OutputAttr, OutputValue, DeviceUri, DeviceAttr, VTUnion +from light9.newtypes import VT, DeviceClass, HexColor, OutputAttr, OutputValue, DeviceUri, DeviceAttr, VTUnion log = logging.getLogger('device') @@ -51,7 +51,7 @@ def _maxColor(values: List[HexColor]) -> def resolve( - deviceType: DeviceUri, # should be DeviceClass? + deviceType: DeviceClass, deviceAttr: DeviceAttr, values: List[VTUnion]) -> VTUnion: # todo: return should be VT """ @@ -80,7 +80,10 @@ def resolve( return max(values) -def toOutputAttrs(deviceType, deviceAttrSettings) -> Dict[OutputAttr, OutputValue]: +def toOutputAttrs( + deviceType: DeviceClass, + deviceAttrSettings: Dict[DeviceAttr, VTUnion # TODO + ]) -> Dict[OutputAttr, OutputValue]: return dict((OutputAttr(u), OutputValue(v)) for u, v in untype_toOutputAttrs(deviceType, deviceAttrSettings).items()) diff --git a/light9/collector/device_test.py b/light9/collector/device_test.py --- a/light9/collector/device_test.py +++ b/light9/collector/device_test.py @@ -1,4 +1,5 @@ import unittest +from light9.newtypes import DeviceAttr, DeviceClass, HexColor, OutputAttr from rdflib import Literal from light9.namespaces import L9 @@ -14,57 +15,45 @@ class TestUnknownDevice(unittest.TestCas class TestColorStrip(unittest.TestCase): def testConvertDeviceToOutputAttrs(self): - out = toOutputAttrs(L9['ChauvetColorStrip'], - {L9['color']: Literal('#ff0000')}) - self.assertEqual( - { - L9['mode']: 215, - L9['red']: 255, - L9['green']: 0, - L9['blue']: 0 - }, out) + out = toOutputAttrs(DeviceClass(L9['ChauvetColorStrip']), {DeviceAttr(L9['color']): HexColor('#ff0000')}) + self.assertEqual({L9['mode']: 215, L9['red']: 255, L9['green']: 0, L9['blue']: 0}, out) class TestDimmer(unittest.TestCase): def testConvert(self): - self.assertEqual({L9['level']: 127}, - toOutputAttrs(L9['SimpleDimmer'], - {L9['brightness']: .5})) + self.assertEqual({L9['level']: 127}, toOutputAttrs(DeviceClass(L9['SimpleDimmer']), {DeviceAttr(L9['brightness']): .5})) class TestMini15(unittest.TestCase): def testConvertColor(self): - out = toOutputAttrs(L9['Mini15'], {L9['color']: '#010203'}) - self.assertEqual(255, out[L9['dimmer']]) - self.assertEqual(1, out[L9['red']]) - self.assertEqual(2, out[L9['green']]) - self.assertEqual(3, out[L9['blue']]) + out = toOutputAttrs(DeviceClass(L9['Mini15']), {DeviceAttr(L9['color']): HexColor('#010203')}) + self.assertEqual(255, out[OutputAttr(L9['dimmer'])]) + self.assertEqual(1, out[OutputAttr(L9['red'])]) + self.assertEqual(2, out[OutputAttr(L9['green'])]) + self.assertEqual(3, out[OutputAttr(L9['blue'])]) def testConvertRotation(self): - out = toOutputAttrs(L9['Mini15'], { - L9['rx']: Literal(90), - L9['ry']: Literal(45) - }) - self.assertEqual(42, out[L9['xRotation']]) - self.assertEqual(127, out[L9['xFine']]) - self.assertEqual(47, out[L9['yRotation']]) - self.assertEqual(207, out[L9['yFine']]) - self.assertEqual(0, out[L9['rotationSpeed']]) + out = toOutputAttrs(DeviceClass(L9['Mini15']), {DeviceAttr(L9['rx']): 90, DeviceAttr(L9['ry']): 45}) + self.assertEqual(42, out[OutputAttr(L9['xRotation'])]) + self.assertEqual(127, out[OutputAttr(L9['xFine'])]) + self.assertEqual(47, out[OutputAttr(L9['yRotation'])]) + self.assertEqual(207, out[OutputAttr(L9['yFine'])]) + self.assertEqual(0, out[OutputAttr(L9['rotationSpeed'])]) + + +DC = DeviceClass(L9['someDev']) class TestResolve(unittest.TestCase): def testMaxes1Color(self): # do not delete - this one catches a bug in the rgb_to_hex(...) lines - self.assertEqual('#ff0300', resolve(None, L9['color'], ['#ff0300'])) + self.assertEqual(HexColor('#ff0300'), resolve(DC, DeviceAttr(L9['color']), [HexColor('#ff0300')])) def testMaxes2Colors(self): - self.assertEqual('#ff0400', - resolve(None, L9['color'], ['#ff0300', '#000400'])) + self.assertEqual(HexColor('#ff0400'), resolve(DC, DeviceAttr(L9['color']), [HexColor('#ff0300'), HexColor('#000400')])) def testMaxes3Colors(self): - self.assertEqual( - '#112233', - resolve(None, L9['color'], ['#110000', '#002200', '#000033'])) + self.assertEqual(HexColor('#112233'), resolve(DC, DeviceAttr(L9['color']), [HexColor('#110000'), HexColor('#002200'), HexColor('#000033')])) diff --git a/light9/collector/dmx_controller_output.py b/light9/collector/dmx_controller_output.py --- a/light9/collector/dmx_controller_output.py +++ b/light9/collector/dmx_controller_output.py @@ -26,7 +26,7 @@ class OpenDmxUsb(): self.stop_bits = 2 self.parity = 'N' self.flow_ctrl = '' - self.rts_state = 0 + self.rts_state = False self._init_dmx() #Initialize the controller @@ -37,7 +37,7 @@ class OpenDmxUsb(): self.ftdi.set_line_property(self.data_bits, self.stop_bits, self.parity, - break_=0) + break_=False) self.ftdi.set_flowctrl(self.flow_ctrl) self.ftdi.purge_rx_buffer() self.ftdi.purge_tx_buffer() @@ -50,15 +50,15 @@ class OpenDmxUsb(): self.ftdi.set_line_property(self.data_bits, self.stop_bits, self.parity, - break_=1) + break_=True) self.ftdi.set_line_property(self.data_bits, self.stop_bits, self.parity, - break_=1) + break_=True) self.ftdi.set_line_property(self.data_bits, self.stop_bits, self.parity, - break_=0) + break_=False) if __name__ == "__main__": diff --git a/light9/collector/output.py b/light9/collector/output.py --- a/light9/collector/output.py +++ b/light9/collector/output.py @@ -1,3 +1,4 @@ +from typing import cast from rdflib import URIRef import socket import struct @@ -5,6 +6,7 @@ import time import usb.core import logging from twisted.internet import threads, reactor, task +from twisted.internet.interfaces import IReactorCore, IReactorTime from light9.metrics import metrics log = logging.getLogger('output') @@ -57,7 +59,7 @@ class Output(object): def crash(self): log.error('unrecoverable- exiting') - reactor.crash() + cast(IReactorCore, reactor).crash() class DummyOutput(Output): @@ -86,13 +88,14 @@ class BackgroundLoopOutput(Output): sendingBuffer = self._currentBuffer def done(worked): - metrics('write_success', output=self.shortId()).incr() - reactor.callLater(max(0, start + 1 / self.rate - time.time()), self._loop) + metrics('write_success', output=self.shortId()).incr() # type: ignore + delay = max(0, start + 1 / self.rate - time.time()) + cast(IReactorTime, reactor).callLater(delay, self._loop) # type: ignore def err(e): - metrics('write_fail', output=self.shortId()).incr() + metrics('write_fail', output=self.shortId()).incr() # type: ignore log.error(e) - reactor.callLater(.2, self._loop) + cast(IReactorTime, reactor).callLater(.2, self._loop) # type: ignore d = threads.deferToThread(self._write, sendingBuffer) d.addCallbacks(done, err) @@ -214,7 +217,7 @@ class Udmx(BackgroundLoopOutput): # for testing fps, smooth fades, etc logAllDmx.debug('%s: %s...' % (self.shortId(), ' '.join(map(str, buf[:32])))) - sent = self.dev.send_multi_value(1, buf) + sent = self.dev.send_multi_value(1, bytearray(buf)) if sent != len(buf): raise ValueError("incomplete send") except ValueError: