47
47
https://github.com/adafruit/circuitpython/releases
48
48
49
49
"""
50
-
51
50
# imports
52
51
import math
53
52
import time
54
53
from micropython import const
55
54
56
55
from adafruit_bus_device .i2c_device import I2CDevice
57
56
57
+ try :
58
+ import typing
59
+ import busio
60
+ from circuitpython_typing import TypeAlias , Union
61
+ from circuitpython_typing import (
62
+ WriteableBuffer ,
63
+ ReadableBuffer ,
64
+ ) # Import ReadableBuffer here
65
+
66
+ from typing import (
67
+ TYPE_CHECKING ,
68
+ List ,
69
+ Tuple ,
70
+ Optional ,
71
+ Iterable ,
72
+ )
73
+
74
+ from PIL import Image
75
+
76
+ except ImportError as e :
77
+ pass
78
+
79
+
58
80
__version__ = "0.0.0+auto.0"
59
81
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_IS31FL3731.git"
60
82
@@ -89,17 +111,25 @@ class IS31FL3731:
89
111
90
112
:param ~busio.I2C i2c: the connected i2c bus i2c_device
91
113
:param int address: the device address; defaults to 0x74
114
+ :param Iterable frames: list of frame indexes to use. int's 0-7.
92
115
"""
93
116
94
- width = 16
95
- height = 9
117
+ width : int = 16
118
+ height : int = 9
96
119
97
- def __init__ (self , i2c , address = 0x74 , frames = None ):
120
+ def __init__ (
121
+ self ,
122
+ i2c : busio .I2C ,
123
+ frames : Optional [Iterable ] = None ,
124
+ address : int = 0x74 ,
125
+ ):
98
126
self .i2c_device = I2CDevice (i2c , address )
99
127
self ._frame = None
100
128
self ._init (frames = frames )
101
129
102
- def _i2c_read_reg (self , reg , result ):
130
+ def _i2c_read_reg (
131
+ self , reg : Optional [int ] = None , result : Optional [WriteableBuffer ] = None
132
+ ) -> Optional [WriteableBuffer ]:
103
133
# Read a buffer of data from the specified 8-bit I2C register address.
104
134
# The provided result parameter will be filled to capacity with bytes
105
135
# of data read from the register.
@@ -108,36 +138,44 @@ def _i2c_read_reg(self, reg, result):
108
138
return result
109
139
return None
110
140
111
- def _i2c_write_reg (self , reg , data ):
141
+ def _i2c_write_reg (
142
+ self , reg : Optional [int ] = None , data : Optional [ReadableBuffer ] = None
143
+ ) -> None :
112
144
# Write a contiguous block of data (bytearray) starting at the
113
145
# specified I2C register address (register passed as argument).
114
146
self ._i2c_write_block (bytes ([reg ]) + data )
115
147
116
- def _i2c_write_block (self , data ) :
148
+ def _i2c_write_block (self , data : Optional [ ReadableBuffer ]) -> None :
117
149
# Write a buffer of data (byte array) to the specified I2C register
118
150
# address.
119
151
with self .i2c_device as i2c :
120
152
i2c .write (data )
121
153
122
- def _bank (self , bank = None ):
154
+ def _bank (self , bank : Optional [ int ] = None ) -> Optional [ int ] :
123
155
if bank is None :
124
156
result = bytearray (1 )
125
157
return self ._i2c_read_reg (_BANK_ADDRESS , result )[0 ]
126
158
self ._i2c_write_reg (_BANK_ADDRESS , bytearray ([bank ]))
127
159
return None
128
160
129
- def _register (self , bank , register , value = None ):
161
+ def _register (
162
+ self ,
163
+ bank : Optional [int ] = None ,
164
+ register : Optional [int ] = None ,
165
+ value : Optional [int ] = None ,
166
+ ) -> Optional [int ]:
130
167
self ._bank (bank )
131
168
if value is None :
132
169
result = bytearray (1 )
133
170
return self ._i2c_read_reg (register , result )[0 ]
134
171
self ._i2c_write_reg (register , bytearray ([value ]))
135
172
return None
136
173
137
- def _mode (self , mode = None ):
174
+ def _mode (self , mode : Optional [int ] = None ) -> int :
175
+ """Function for setting _register mode"""
138
176
return self ._register (_CONFIG_BANK , _MODE_REGISTER , mode )
139
177
140
- def _init (self , frames = None ) :
178
+ def _init (self , frames : Iterable ) -> None :
141
179
self .sleep (True )
142
180
# Clear config; sets to Picture Mode, no audio sync, maintains sleep
143
181
self ._bank (_CONFIG_BANK )
@@ -154,21 +192,26 @@ def _init(self, frames=None):
154
192
self ._frame = 0 # To match config bytes above
155
193
self .sleep (False )
156
194
157
- def reset (self ):
195
+ def reset (self ) -> None :
158
196
"""Kill the display for 10MS"""
159
197
self .sleep (True )
160
198
time .sleep (0.01 ) # 10 MS pause to reset.
161
199
self .sleep (False )
162
200
163
- def sleep (self , value ) :
201
+ def sleep (self , value : bool ) -> Optional [ int ] :
164
202
"""
165
203
Set the Software Shutdown Register bit
166
204
167
205
:param value: True to set software shutdown bit; False unset
168
206
"""
169
207
return self ._register (_CONFIG_BANK , _SHUTDOWN_REGISTER , not value )
170
208
171
- def autoplay (self , delay = 0 , loops = 0 , frames = 0 ):
209
+ def autoplay (
210
+ self ,
211
+ delay : int = 0 ,
212
+ loops : int = 0 ,
213
+ frames : int = 0 ,
214
+ ) -> None :
172
215
"""
173
216
Start autoplay
174
217
@@ -190,15 +233,20 @@ def autoplay(self, delay=0, loops=0, frames=0):
190
233
self ._register (_CONFIG_BANK , _AUTOPLAY2_REGISTER , delay % 64 )
191
234
self ._mode (_AUTOPLAY_MODE | self ._frame )
192
235
193
- def fade (self , fade_in = None , fade_out = None , pause = 0 ):
236
+ def fade (
237
+ self ,
238
+ fade_in : Optional [int ] = None ,
239
+ fade_out : Optional [int ] = None ,
240
+ pause : int = 0 ,
241
+ ) -> int :
194
242
"""
195
243
Start and stop the fade feature. If both fade_in and fade_out are None (the
196
244
default), the breath feature is used for fading. if fade_in is None, then
197
245
fade_in = fade_out. If fade_out is None, then fade_out = fade_in
198
246
199
- :param fade_in: positive number; 0->100
200
- :param fade-out: positive number; 0->100
201
- :param pause: breath register 2 pause value
247
+ :param fade_in: int positive number; 0->100
248
+ :param fade-out: int positive number; 0->100
249
+ :param pause: int breath register 2 pause value
202
250
"""
203
251
if fade_in is None and fade_out is None :
204
252
self ._register (_CONFIG_BANK , _BREATH2_REGISTER , 0 )
@@ -223,12 +271,12 @@ def fade(self, fade_in=None, fade_out=None, pause=0):
223
271
self ._register (_CONFIG_BANK , _BREATH1_REGISTER , fade_out << 4 | fade_in )
224
272
self ._register (_CONFIG_BANK , _BREATH2_REGISTER , 1 << 4 | pause )
225
273
226
- def frame (self , frame = None , show = True ):
274
+ def frame (self , frame : Optional [ int ] = None , show : bool = True ) -> Optional [ int ] :
227
275
"""
228
276
Set the current frame
229
277
230
- :param frame: frame number; 0-7 or None. If None function returns current frame
231
- :param show: True to show the frame; False to not show.
278
+ :param frame: int frame number; 0-7 or None. If None function returns current frame
279
+ :param show: bool True to show the frame; False to not show.
232
280
"""
233
281
if frame is None :
234
282
return self ._frame
@@ -239,11 +287,17 @@ def frame(self, frame=None, show=True):
239
287
self ._register (_CONFIG_BANK , _FRAME_REGISTER , frame )
240
288
return None
241
289
242
- def audio_sync (self , value = None ) :
290
+ def audio_sync (self , value : Optional [ int ]) -> Optional [ int ] :
243
291
"""Set the audio sync feature register"""
244
292
return self ._register (_CONFIG_BANK , _AUDIOSYNC_REGISTER , value )
245
293
246
- def audio_play (self , sample_rate , audio_gain = 0 , agc_enable = False , agc_fast = False ):
294
+ def audio_play (
295
+ self ,
296
+ sample_rate : int ,
297
+ audio_gain : int = 0 ,
298
+ agc_enable : bool = False ,
299
+ agc_fast : bool = False ,
300
+ ) -> None :
247
301
"""Controls the audio play feature"""
248
302
if sample_rate == 0 :
249
303
self ._mode (_PICTURE_MODE )
@@ -262,7 +316,7 @@ def audio_play(self, sample_rate, audio_gain=0, agc_enable=False, agc_fast=False
262
316
)
263
317
self ._mode (_AUDIOPLAY_MODE )
264
318
265
- def blink (self , rate = None ):
319
+ def blink (self , rate : Optional [ int ] = None ) -> Optional [ int ] :
266
320
"""Updates the blink register"""
267
321
# pylint: disable=no-else-return
268
322
# This needs to be refactored when it can be tested
@@ -275,13 +329,18 @@ def blink(self, rate=None):
275
329
self ._register (_CONFIG_BANK , _BLINK_REGISTER , rate & 0x07 | 0x08 )
276
330
return None
277
331
278
- def fill (self , color = None , blink = None , frame = None ):
332
+ def fill (
333
+ self ,
334
+ color : Optional [int ] = None ,
335
+ frame : Optional [int ] = None ,
336
+ blink : bool = False ,
337
+ ):
279
338
"""
280
339
Fill the display with a brightness level
281
340
282
341
:param color: brightness 0->255
283
- :param blink: True if blinking is required
284
- :param frame: which frame to fill 0->7
342
+ :param blink: bool True to blink
343
+ :param frame: int the frame to set the pixel, default 0
285
344
"""
286
345
if frame is None :
287
346
frame = self ._frame
@@ -301,35 +360,72 @@ def fill(self, color=None, blink=None, frame=None):
301
360
302
361
# This function must be replaced for each board
303
362
@staticmethod
304
- def pixel_addr (x , y ) :
363
+ def pixel_addr (x : int , y : int ) -> int :
305
364
"""Calulate the offset into the device array for x,y pixel"""
306
365
return x + y * 16
307
366
308
367
# pylint: disable-msg=too-many-arguments
309
- def pixel (self , x , y , color = None , blink = None , frame = None ):
368
+ def pixel (
369
+ self ,
370
+ x : int ,
371
+ y : int ,
372
+ color : Optional [int ] = None ,
373
+ frame : Optional [int ] = None ,
374
+ blink : bool = False ,
375
+ rotate : int = 0 ,
376
+ ) -> Optional [int ]:
310
377
"""
311
- Blink or brightness for x-, y-pixel
312
-
313
- :param x: horizontal pixel position
314
- :param y: vertical pixel position
315
- :param color: brightness value 0->255
316
- :param blink: True to blink
317
- :param frame: the frame to set the pixel
378
+ Matrix display configuration
379
+
380
+ :param x: int horizontal pixel position
381
+ :param y: int vertical pixel position
382
+ :param color: int brightness value 0->255
383
+ :param blink: bool True to blink
384
+ :param frame: int the frame to set the pixel, default 0
385
+ :param rotate: int display rotation (0, 90, 180, 270)
318
386
"""
319
- if not 0 <= x <= self .width :
320
- return None
321
- if not 0 <= y <= self .height :
322
- return None
323
- pixel = self .pixel_addr (x , y )
387
+ # pylint: disable=too-many-branches
388
+
389
+ if rotate not in (0 , 90 , 180 , 270 ):
390
+ raise ValueError ("Rotation must be 0, 90, 180, or 270 degrees" )
391
+
392
+ if rotate == 0 :
393
+ check_x = 0 <= x <= self .width
394
+ check_y = 0 <= y <= self .height
395
+ if not (check_x and check_y ):
396
+ return None
397
+ pixel = self .pixel_addr (x , y )
398
+ elif rotate == 90 :
399
+ check_x = 0 <= y <= self .width
400
+ check_y = 0 <= x <= self .height
401
+ if not (check_x and check_y ):
402
+ return None
403
+ pixel = self .pixel_addr (y , self .height - x - 1 )
404
+ elif rotate == 180 :
405
+ check_x = 0 <= x <= self .width
406
+ check_y = 0 <= y <= self .height
407
+ if not (check_x and check_y ):
408
+ return None
409
+ pixel = self .pixel_addr (self .width - x - 1 , self .height - y - 1 )
410
+ elif rotate == 270 :
411
+ check_x = 0 <= y <= self .width
412
+ check_y = 0 <= x <= self .height
413
+ if not (check_x and check_y ):
414
+ return None
415
+ pixel = self .pixel_addr (self .width - y - 1 , x )
416
+
324
417
if color is None and blink is None :
325
418
return self ._register (self ._frame , pixel )
419
+ # frames other than 0 only used in animation. allow None.
326
420
if frame is None :
327
421
frame = self ._frame
422
+ # Brightness
328
423
if color is not None :
329
424
if not 0 <= color <= 255 :
330
- raise ValueError ("Color out of range" )
425
+ raise ValueError ("Brightness or Color out of range (0-255) " )
331
426
self ._register (frame , _COLOR_OFFSET + pixel , color )
332
- if blink is not None :
427
+ # Blink works but not well while animated
428
+ if blink :
333
429
addr , bit = divmod (pixel , 8 )
334
430
bits = self ._register (frame , _BLINK_OFFSET + addr )
335
431
if blink :
@@ -341,13 +437,15 @@ def pixel(self, x, y, color=None, blink=None, frame=None):
341
437
342
438
# pylint: enable-msg=too-many-arguments
343
439
344
- def image (self , img , blink = None , frame = None ):
440
+ def image (
441
+ self , img : Image , frame : Optional [int ] = None , blink : bool = False
442
+ ) -> None :
345
443
"""Set buffer to value of Python Imaging Library image. The image should
346
444
be in 8-bit mode (L) and a size equal to the display size.
347
445
348
446
:param img: Python Imaging Library image
349
447
:param blink: True to blink
350
- :param frame: the frame to set the image
448
+ :param frame: the frame to set the image, default 0
351
449
"""
352
450
if img .mode != "L" :
353
451
raise ValueError ("Image must be in mode L." )
0 commit comments