Skip to content

Commit 2524763

Browse files
small changes
1 parent ffd9806 commit 2524763

File tree

9 files changed

+128
-97
lines changed

9 files changed

+128
-97
lines changed

.github/workflows/pre-commit.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
name: Pre-Commit
22

3-
on:
4-
pull_request:
5-
branches: [main, master]
3+
on: [push, pull_request]
64

75
jobs:
86
main:

.github/workflows/run_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Tests
22

3-
on: [push]
3+
on: [push, pull_request]
44

55
jobs:
66
test:

src/pyartnet/base/base_node.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class BaseNode(Generic[TYPE_U], OutputCorrection):
2121
def __init__(self, ip: str, port: int, *,
2222
max_fps: int = 25,
2323
refresh_every: Union[int, float, None] = 2, start_refresh_task: bool = True,
24-
source_address: Optional[Tuple[str, int]] = None):
24+
source_address: Optional[Tuple[str, int]] = None) -> None:
2525
super().__init__()
2626

2727
# Destination
@@ -60,7 +60,7 @@ def __init__(self, ip: str, port: int, *,
6060
self._universes: Tuple[TYPE_U, ...] = ()
6161
self._universe_map: Dict[int, TYPE_U] = {}
6262

63-
def _apply_output_correction(self):
63+
def _apply_output_correction(self) -> None:
6464
for u in self._universes:
6565
u._apply_output_correction()
6666

@@ -70,7 +70,7 @@ def _send_universe(self, id: int, byte_size: int, values: bytearray, universe: T
7070
def set_synchronous_mode(self, enabled: bool):
7171
raise NotImplementedError()
7272

73-
def _send_synchronization(self):
73+
def _send_synchronization(self) -> None:
7474
pass
7575

7676
def _send_data(self, data: Union[bytearray, bytes]) -> int:
@@ -80,7 +80,7 @@ def _send_data(self, data: Union[bytearray, bytes]) -> int:
8080
self._last_send = monotonic()
8181
return ret
8282

83-
async def _process_values_task(self):
83+
async def _process_values_task(self) -> None:
8484
# wait a little, so we can schedule multiple tasks/updates, and they all start together
8585
await sleep(0.01)
8686

@@ -113,15 +113,15 @@ async def _process_values_task(self):
113113

114114
await sleep(self._process_every)
115115

116-
def start_refresh(self):
116+
def start_refresh(self) -> None:
117117
"""Manually start the refresh task (if not already running)"""
118118
self._refresh_task.start()
119119

120-
def stop_refresh(self):
120+
def stop_refresh(self) -> None:
121121
"""Manually stop the refresh task"""
122122
self._refresh_task.cancel()
123123

124-
async def _periodic_refresh_worker(self):
124+
async def _periodic_refresh_worker(self) -> None:
125125
while True:
126126
# sync the refresh messages
127127
next_refresh = monotonic()
@@ -144,27 +144,25 @@ def get_universe(self, nr: int) -> TYPE_U:
144144
:param nr: universe nr
145145
:return: The universe
146146
"""
147-
if not isinstance(nr, int) or not nr >= 0:
148-
raise ValueError('BaseUniverse must be an int >= 0!')
149-
nr = int(nr)
147+
nr = self._validate_universe_nr(nr)
150148

151149
try:
152150
return self._universe_map[nr]
153151
except KeyError:
154-
raise UniverseNotFoundError(f'BaseUniverse {nr:d} not found!') from None
152+
msg = f'BaseUniverse {nr:d} not found!'
153+
raise UniverseNotFoundError(msg) from None
155154

156155
def add_universe(self, nr: int = 0) -> TYPE_U:
157156
"""Creates a new universe and adds it to the parent node
158157
159158
:param nr: universe nr
160159
:return: The universe
161160
"""
162-
if not isinstance(nr, int) or not nr >= 0:
163-
raise ValueError('BaseUniverse must be an int >= 0!')
164-
nr = int(nr)
161+
nr = self._validate_universe_nr(nr)
165162

166163
if nr in self._universe_map:
167-
raise DuplicateUniverseError(f'BaseUniverse {nr:d} does already exist!')
164+
msg = f'BaseUniverse {nr:d} does already exist!'
165+
raise DuplicateUniverseError(msg)
168166

169167
# add to data
170168
self._universe_map[nr] = universe = self._create_universe(nr)
@@ -175,6 +173,9 @@ def add_universe(self, nr: int = 0) -> TYPE_U:
175173
def _create_universe(self, nr: int) -> TYPE_U:
176174
raise NotImplementedError()
177175

176+
def _validate_universe_nr(self, nr: int) -> int:
177+
raise NotImplementedError()
178+
178179
def __await__(self):
179180
while self._process_jobs:
180181
for job in self._process_jobs:
@@ -183,5 +184,5 @@ def __await__(self):
183184
def __getitem__(self, nr: int) -> TYPE_U:
184185
return self.get_universe(nr)
185186

186-
def __len__(self):
187+
def __len__(self) -> int:
187188
return len(self._universes)

src/pyartnet/impl_artnet/node.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def __init__(self, ip: str, port: int, *,
2222

2323
# ArtNet specific fields
2424
sequence_counter: bool = True
25-
):
25+
) -> None:
2626
super().__init__(ip=ip, port=port,
2727
max_fps=max_fps,
2828
refresh_every=refresh_every, start_refresh_task=start_refresh_task,
@@ -40,21 +40,21 @@ def __init__(self, ip: str, port: int, *,
4040
self._sync_enabled : bool = False
4141

4242
def _send_universe(self, id: int, byte_size: int, values: bytearray,
43-
universe: 'pyartnet.impl_artnet.ArtNetUniverse'):
43+
universe: 'pyartnet.impl_artnet.ArtNetUniverse') -> None:
4444

4545
# pre allocate the bytearray
4646
_size = 10 + byte_size
4747
packet = bytearray(_size)
4848

49-
packet[0:2] =[0x00, 0x50] # Opcode ArtDMX 0x5000 (Little endian)
50-
packet[2:4] = [0x00, 0x0e] # Protocol version 14
49+
packet[0:2] = (0x00, 0x50) # 2 | Opcode ArtDMX 0x5000 (Little Endian)
50+
packet[2:4] = (0x00, 0x0e) # 2 | Protocol version 14 (Little Endian)
5151

52-
packet[4] = self._sequence_ctr.value # 1 | Sequence,
53-
packet[5] = 0x00 # 1 | Physical input port (not used)
54-
packet[6:8] = id.to_bytes(2, byteorder='little') # 2 | Universe
52+
packet[4] = self._sequence_ctr.value # 1 | Sequence,
53+
packet[5] = 0x00 # 1 | Physical input port (not used)
54+
packet[6:8] = id.to_bytes(2, 'little') # 2 | Universe (Little endian)
5555

56-
packet[8:10] = byte_size.to_bytes(2, 'big') # 2 | Number of channels Big Endian
57-
packet[10: _size] = values # 0 - 512 | Channel values
56+
packet[8:10] = byte_size.to_bytes(2, 'big') # 2 | Number of channels Big Endian
57+
packet[10: _size] = values # 0 - 512 | Channel values
5858

5959
self._send_data(packet)
6060

@@ -67,7 +67,14 @@ def _create_universe(self, nr: int) -> 'pyartnet.impl_artnet.ArtNetUniverse':
6767
raise InvalidUniverseAddressError()
6868
return pyartnet.impl_artnet.ArtNetUniverse(self, nr)
6969

70-
def __log_artnet_frame(self, p: Union[bytearray, bytes]):
70+
def _validate_universe_nr(self, nr: int) -> int:
71+
if not isinstance(nr, int):
72+
raise TypeError()
73+
if not 0 <= nr <= 32_768:
74+
raise InvalidUniverseAddressError()
75+
return int(nr)
76+
77+
def __log_artnet_frame(self, p: Union[bytearray, bytes]) -> None:
7178
"""Log Artnet Frame"""
7279
assert isinstance(p, (bytearray, bytes))
7380

@@ -134,20 +141,25 @@ def __log_artnet_frame(self, p: Union[bytearray, bytes]):
134141
log.debug(out)
135142

136143
def set_synchronous_mode(self, enabled: bool):
144+
if self._refresh_every > 3.5:
145+
msg = 'ArtNet synchronization requires refresh_every <= 3.5s'
146+
raise ValueError(msg)
147+
137148
self._sync_enabled = enabled
149+
return self
138150

139-
def _send_synchronization(self):
151+
def _send_synchronization(self) -> None:
140152
if not self._sync_enabled:
141153
return
142154

143155
# pre allocate the bytearray
144156
packet = bytearray(6)
145157

146-
packet[0:2] = [0x00, 0x52] # Opcode ArtSync
147-
packet[2:4] = [0x00, 0x0e] # Protocol version 14
158+
packet[0:2] = (0x00, 0x52) # 2 | Opcode ArtSync 0x5200 (Little Endian)
159+
packet[2:4] = (0x00, 0x0e) # 2 | Protocol Version 14 (Little Endian)
148160

149-
packet[4] = 0 # Aux1
150-
packet[5] = 0 # Aux2
161+
packet[4] = 0 # 1 | Aux1
162+
packet[5] = 0 # 1 | Aux2
151163

152164
self._send_data(packet)
153165

src/pyartnet/impl_kinet/node.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class KiNetNode(BaseNode['pyartnet.impl_kinet.KiNetUniverse']):
1919
def __init__(self, ip: str, port: int, *,
2020
max_fps: int = 25,
2121
refresh_every: Union[int, float, None] = 2, start_refresh_task: bool = True,
22-
source_address: Optional[Tuple[str, int]] = None):
22+
source_address: Optional[Tuple[str, int]] = None) -> None:
2323
super().__init__(ip=ip, port=port,
2424
max_fps=max_fps,
2525
refresh_every=refresh_every, start_refresh_task=start_refresh_task,
@@ -31,7 +31,8 @@ def __init__(self, ip: str, port: int, *,
3131
packet.extend(s_pack(">IBBHI", 0, 0, 0, 0, 0xFFFFFFFF)) # sequence, port, padding, flags, timer
3232
self._packet_base = bytes(packet)
3333

34-
def _send_universe(self, id: int, byte_size: int, values: bytearray, universe: 'pyartnet.impl_kinet.KiNetUniverse'):
34+
def _send_universe(self, id: int, byte_size: int,
35+
values: bytearray, universe: 'pyartnet.impl_kinet.KiNetUniverse') -> None:
3536
packet = bytearray()
3637
packet.append(byte_size)
3738
packet.extend(values)
@@ -43,6 +44,11 @@ def _send_universe(self, id: int, byte_size: int, values: bytearray, universe: '
4344
log.debug(f"Sending KiNet frame to {self._ip}:{self._port}: {(self._packet_base + packet).hex()}")
4445

4546
def _create_universe(self, nr: int) -> 'pyartnet.impl_kinet.KiNetUniverse':
46-
if nr >= 32_768:
47+
return pyartnet.impl_kinet.KiNetUniverse(self, self._validate_universe_nr(nr))
48+
49+
def _validate_universe_nr(self, nr: int) -> int:
50+
if not isinstance(nr, int):
51+
raise TypeError()
52+
if not 0 <= nr <= 32_768:
4753
raise InvalidUniverseAddressError()
48-
return pyartnet.impl_kinet.KiNetUniverse(self, nr)
54+
return int(nr)

src/pyartnet/impl_sacn/node.py

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from uuid import uuid4
66

77
import pyartnet.impl_sacn.universe
8-
from pyartnet.base import BaseNode
8+
from pyartnet.base import BaseNode, SequenceCounter
99
from pyartnet.errors import InvalidCidError, InvalidUniverseAddressError
1010

1111
# -----------------------------------------------------------------------------
@@ -35,7 +35,7 @@ def __init__(self, ip: str, port: int, *,
3535

3636
# sACN E1.31 specific fields
3737
cid: Optional[bytes] = None, source_name: Optional[str] = None
38-
):
38+
) -> None:
3939
super().__init__(ip=ip, port=port,
4040
max_fps=max_fps,
4141
refresh_every=refresh_every, start_refresh_task=start_refresh_task,
@@ -63,28 +63,28 @@ def __init__(self, ip: str, port: int, *,
6363
packet.extend(b'\x00\x10') # | 2 | Preamble Size
6464
packet.extend(b'\x00\x00') # | 2 | Post-amble Size
6565
packet.extend(ACN_PACKET_IDENTIFIER) # | 12 | Packet Identifier
66-
packet.extend([0x72, 0x57]) # | 2 | Flags, Length
66+
packet.extend((0x72, 0x57)) # | 2 | Flags, Length
6767
packet.extend(VECTOR_ROOT_E131_DATA) # | 4 | Vector
6868
packet.extend(cid) # | 16 | CID, a unique identifier
6969

7070
self._packet_base: bytearray = packet
7171

7272
self._synchronization_address : int = 0
73-
self._sync_sequence_number : int = 0
73+
self._sync_sequence_number: Final = SequenceCounter()
7474

7575

7676
def _send_universe(self, id: int, byte_size: int, values: bytearray,
77-
universe: 'pyartnet.impl_sacn.universe.SacnUniverse'):
77+
universe: 'pyartnet.impl_sacn.universe.SacnUniverse') -> None:
7878
packet = bytearray()
7979

8080
# DMX Start Code is not included in the byte size from the universe
8181
prop_count = byte_size + 1
8282

8383
# Framing layer Part 1
84-
packet.extend((( 87 + prop_count) | 0x7000).to_bytes(2, 'big')) # Flags and Length
85-
packet.extend(VECTOR_E131_DATA_PACKET) # | 4 | Vector
86-
packet.extend(self._source_name_byte) # | 64 |Source Name
87-
packet.append(100) # | 1 |Priority
84+
packet.extend((( 87 + prop_count) | 0x7000).to_bytes(2, 'big')) # | 2 | Flags and Length
85+
packet.extend(VECTOR_E131_DATA_PACKET) # | 4 | Vector
86+
packet.extend(self._source_name_byte) # | 64 | Source Name
87+
packet.append(100) # | 1 | Priority
8888
packet.extend(int(self._synchronization_address).to_bytes(2, 'big')) # | 2 | Synchronization universe
8989

9090
# Framing layer Part 2
@@ -104,9 +104,10 @@ def _send_universe(self, id: int, byte_size: int, values: bytearray,
104104
packet.append(0x00) # | 1 | Property Values - DMX Start Code
105105
packet.extend(values) # | 0-512 | Property Values - DMX Data
106106

107-
# Update length for base packet
107+
# Update length and package type for base packet
108108
base_packet = self._packet_base
109-
base_packet[16:18] = ((109 + prop_count) | 0x7000).to_bytes(2, 'big') # root layer
109+
base_packet[16:18] = ((109 + prop_count) | 0x7000).to_bytes(2, 'big') # | 2 | Flags, Length
110+
base_packet[18:22] = VECTOR_ROOT_E131_DATA # | 4 | Vector
110111

111112
self._send_data(packet)
112113

@@ -115,43 +116,46 @@ def _send_universe(self, id: int, byte_size: int, values: bytearray,
115116
log.debug(f"Sending sACN frame to {self._ip}:{self._port}: {(base_packet + packet).hex()}")
116117

117118
def _create_universe(self, nr: int) -> 'pyartnet.impl_sacn.SacnUniverse':
118-
# 6.2.7 E1.31 Data Packet: Universe
119-
if not 1 <= nr < 63_999:
119+
return pyartnet.impl_sacn.SacnUniverse(self, self._validate_universe_nr(nr))
120+
121+
def _validate_universe_nr(self, nr: int) -> int:
122+
if not isinstance(nr, int):
123+
raise TypeError()
124+
# See spec 6.2.7 E1.31 Data Packet: Universe
125+
if not 1 <= nr <= 63_999:
120126
raise InvalidUniverseAddressError()
121-
return pyartnet.impl_sacn.SacnUniverse(self, nr)
127+
return int(nr)
128+
122129

123-
def set_synchronous_mode(self, enabled: bool, synchronization_address : int = 0):
130+
def set_synchronous_mode(self, enabled: bool, synchronization_address: int = 0):
124131
if enabled:
125-
assert(synchronization_address != 0)
126-
self._synchronization_address = synchronization_address
132+
self._synchronization_address = self._validate_universe_nr(synchronization_address)
127133
else:
128-
assert(synchronization_address == 0)
134+
if synchronization_address != 0:
135+
msg = 'synchronization_address must be 0 when disabling synchronous mode!'
136+
raise ValueError(msg)
129137
self._synchronization_address = 0
130138

131-
def _send_synchronization(self):
132-
if (self._synchronization_address == 0):
139+
def _send_synchronization(self) -> None:
140+
if not self._synchronization_address:
133141
return
134142

135143
packet = bytearray()
136144

137-
try:
138-
base_packet = self._packet_base
139-
base_packet[16:18] = ((33) | 0x7000).to_bytes(2, 'big') # root layer
140-
base_packet[18:22] = VECTOR_ROOT_E131_EXTENDED
141-
# Framing layer
142-
packet.extend(((11) | 0x7000).to_bytes(2, 'big')) # | 2 | Flags and Length
143-
packet.extend(VECTOR_E131_EXTENDED_SYNCHRONIZATION) # | 4 | Vector
144-
self._sync_sequence_number += 1
145-
if (self._sync_sequence_number >= 255):
146-
self._sync_sequence_number = 0
147-
packet.append(self._sync_sequence_number) # | 1 | Sequence Number
148-
packet.extend(self._synchronization_address.to_bytes(2, 'big')) # | 2 | Synchronization universe
149-
packet.extend([0, 0]) # | 2 | Reserved
150-
151-
self._send_data(packet)
152-
153-
if log.isEnabledFor(LVL_DEBUG):
154-
# log complete packet
155-
log.debug(f"Sending sACN Syncronization Packet to {self._ip}:{self._port}: {(base_packet + packet).hex()}")
156-
finally:
157-
self._packet_base[18:22] = VECTOR_ROOT_E131_DATA
145+
# Framing layer
146+
packet.extend((11 | 0x7000).to_bytes(2, 'big')) # | 2 | Flags and Length
147+
packet.extend(VECTOR_E131_EXTENDED_SYNCHRONIZATION) # | 4 | Vector
148+
packet.append(self._sync_sequence_number.value) # | 1 | Sequence Number
149+
packet.extend(self._synchronization_address.to_bytes(2, 'big')) # | 2 | Synchronization universe
150+
packet.extend([0, 0]) # | 2 | Reserved
151+
152+
# Update length and package type for base packet
153+
base_packet = self._packet_base
154+
base_packet[16:18] = (33 | 0x7000).to_bytes(2, 'big') # | 2 | Flags, Length
155+
base_packet[18:22] = VECTOR_ROOT_E131_EXTENDED # | 4 | Vector
156+
157+
self._send_data(packet)
158+
159+
if log.isEnabledFor(LVL_DEBUG):
160+
# log complete packet
161+
log.debug(f"Sending sACN Synchronization Packet to {self._ip}:{self._port}: {(base_packet + packet).hex()}")

0 commit comments

Comments
 (0)