@@ -17,6 +17,8 @@ class StreamDeckNeo(StreamDeck):
1717 KEY_COLS = 4
1818 KEY_ROWS = 2
1919
20+ TOUCH_KEY_COUNT = 2
21+
2022 KEY_PIXEL_WIDTH = 96
2123 KEY_PIXEL_HEIGHT = 96
2224 KEY_IMAGE_FORMAT = "JPEG"
@@ -26,6 +28,12 @@ class StreamDeckNeo(StreamDeck):
2628 DECK_TYPE = "Stream Deck Neo"
2729 DECK_VISUAL = True
2830
31+ SCREEN_PIXEL_WIDTH = 248
32+ SCREEN_PIXEL_HEIGHT = 58
33+ SCREEN_IMAGE_FORMAT = "JPEG"
34+ SCREEN_FLIP = (True , True )
35+ SCREEN_ROTATION = 0
36+
2937 IMAGE_REPORT_LENGTH = 1024
3038 IMAGE_REPORT_HEADER_LENGTH = 8
3139 IMAGE_REPORT_PAYLOAD_LENGTH = IMAGE_REPORT_LENGTH - IMAGE_REPORT_HEADER_LENGTH
@@ -75,8 +83,24 @@ class StreamDeckNeo(StreamDeck):
7583 0x02 , 0x8a , 0x28 , 0xa0 , 0x02 , 0x8a , 0x28 , 0xa0 , 0x0f , 0xff , 0xd9
7684 ]
7785
86+ # 248 x 58 black JPEG
87+ BLANK_SCREEN_IMAGE = [
88+ 0xff , 0xd8 , 0xff , 0xe0 , 0x00 , 0x10 , 0x4a , 0x46 , 0x49 , 0x46 , 0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x00 , 0x01 , 0x00 ,
89+ 0x00 , 0xff , 0xdb , 0x00 , 0x43 , 0x00 , 0x08 , 0x06 , 0x06 , 0x07 , 0x06 , 0x05 , 0x08 , 0x07 , 0x07 , 0x07 , 0x09 , 0x09 , 0x08 ,
90+ 0x0a , 0x0c , 0x14 , 0x0d , 0x0c , 0x0b , 0x0b , 0x0c , 0x19 , 0x12 , 0x13 , 0x0f , 0x14 , 0x1d , 0x1a , 0x1f , 0x1e , 0x1d , 0x1a ,
91+ 0x1c , 0x1c , 0x20 , 0x24 , 0x2e , 0x27 , 0x20 , 0x22 , 0x2c , 0x23 , 0x1c , 0x1c , 0x28 , 0x37 , 0x29 , 0x2c , 0x30 , 0x31 , 0x34 ,
92+ 0x34 , 0x34 , 0x1f , 0x27 , 0x39 , 0x3d , 0x38 , 0x32 , 0x3c , 0x2e , 0x33 , 0x34 , 0x32 , 0xff , 0xc0 , 0x00 , 0x0b , 0x08 , 0x00 ,
93+ 0x3a , 0x00 , 0xf8 , 0x01 , 0x01 , 0x11 , 0x00 , 0xff , 0xc4 , 0x00 , 0x15 , 0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
94+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x08 , 0xff , 0xc4 , 0x00 , 0x14 , 0x10 , 0x01 , 0x00 , 0x00 ,
95+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xff , 0xda , 0x00 , 0x08 , 0x01 ,
96+ 0x01 , 0x00 , 0x00 , 0x3f , 0x00 , 0x9f , 0xc0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
97+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
98+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
99+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x7f , 0xff , 0xd9
100+ ]
101+
78102 def _read_control_states (self ):
79- states = self .device .read (4 + self .KEY_COUNT )
103+ states = self .device .read (4 + self .KEY_COUNT + self . TOUCH_KEY_COUNT )
80104 if states is None :
81105 return None
82106
@@ -114,7 +138,7 @@ def get_firmware_version(self):
114138 return self ._extract_string (version [6 :])
115139
116140 def set_key_image (self , key , image ):
117- if min (max (key , 0 ), self .KEY_COUNT ) != key :
141+ if min (max (key , 0 ), self .KEY_COUNT - 1 ) != key :
118142 raise IndexError ("Invalid key index {}." .format (key ))
119143
120144 image = bytes (image or self .BLANK_KEY_IMAGE )
@@ -143,5 +167,46 @@ def set_key_image(self, key, image):
143167 bytes_remaining = bytes_remaining - this_length
144168 page_number = page_number + 1
145169
170+ def set_key_color (self , key , r , g , b ):
171+ if min (max (key , 0 ), self .KEY_COUNT + self .TOUCH_KEY_COUNT - 1 ) != key :
172+ raise IndexError ("Invalid touch key index {}." .format (key ))
173+
174+ if r > 255 or r < 0 or g > 255 or g < 0 or b > 255 or b < 0 :
175+ raise ValueError ("Invalid color" )
176+
177+ payload = bytearray (32 )
178+ payload [0 :6 ] = [0x03 , 0x06 , key , r , g , b ]
179+ self .device .write_feature (payload )
180+
181+ def set_screen_image (self , image ):
182+ if not image :
183+ image = self .BLANK_SCREEN_IMAGE
184+
185+ image = bytes (image )
186+
187+ page_number = 0
188+ bytes_remaining = len (image )
189+ while bytes_remaining > 0 :
190+ this_length = min (bytes_remaining , self .IMAGE_REPORT_PAYLOAD_LENGTH )
191+ bytes_sent = page_number * self .IMAGE_REPORT_PAYLOAD_LENGTH
192+
193+ header = [
194+ 0x02 , # 0
195+ 0x0b , # 1
196+ 0x00 , # 2
197+ 0x01 if this_length == bytes_remaining else 0x00 , # 3 is the last report?
198+ this_length & 0xff , # 5 bytecount high byte
199+ (this_length >> 8 ) & 0xff , # 4 bytecount high byte
200+ page_number & 0xff , # 7 pagenumber low byte
201+ (page_number >> 8 ) & 0xff # 6 pagenumber high byte
202+ ]
203+
204+ payload = bytes (header ) + image [bytes_sent :bytes_sent + this_length ]
205+ padding = bytearray (self .IMAGE_REPORT_LENGTH - len (payload ))
206+ self .device .write (payload + padding )
207+
208+ bytes_remaining = bytes_remaining - this_length
209+ page_number = page_number + 1
210+
146211 def set_touchscreen_image (self , image , x_pos = 0 , y_pos = 0 , width = 0 , height = 0 ):
147212 pass
0 commit comments