-
Notifications
You must be signed in to change notification settings - Fork 0
/
models.py
126 lines (109 loc) · 4.92 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env viam-wrap
import codecs
import sys
from typing import Mapping, Optional
from typing_extensions import Self
import viam_wrap
from viam.components.generic import Generic
from viam.module.types import Reconfigurable
from viam.proto.app.robot import ComponentConfig
from viam.proto.common import ResourceName
from viam.utils import ValueTypes
from viam.resource.base import ResourceBase
from viam.resource.types import Model, ModelFamily
from viam.components.generic import Generic
from google.protobuf import json_format
from viam.services.service_base import ServiceBase
from viam import logging
from viam.components.camera import Camera
from luma.core.interface.serial import spi, noop
from luma.core.render import canvas
from luma.core.legacy import text
from luma.core.legacy.font import proportional, LCD_FONT, CP437_FONT
from luma.led_matrix.device import max7219
class MAX7219(Generic):
MODEL = 'michaellee1019:led_matrix:max7219'
serial = None
device = None
@classmethod
def new(self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]) -> Self:
output = self(config.name)
output.reconfigure(config, dependencies)
return output
async def do_command(
self,
command: Mapping[str, ValueTypes],
*,
timeout: Optional[float] = None,
**kwargs
) -> Mapping[str, ValueTypes]:
result = {key: False for key in command.keys()}
drawings = command.get("drawings")
with canvas(self.device) as draw:
for drawing in drawings:
match drawing["type"]:
case "border":
self.border(draw)
case "rectangle":
pixels = drawing["pixels"]
self.rectangle(draw, pixels)
case "text":
message = drawing["message"]
start_pixel = drawing["start_pixel"]
font = drawing.get("font")
self.text(draw, start_pixel, message, font)
case "point":
pixel = drawing["pixel"]
self.point(draw, pixel)
case "line":
pixels = drawing["pixels"]
width = drawing.get("width")
self.line(draw, pixels, width)
case "clear":
self.clear()
result["drawings"] = True
return result
def border(self, draw):
draw.rectangle(self.device.bounding_box, outline="white")
def rectangle(self, draw, pixels: list[int]):
draw.rectangle(pixels, outline="white")
def text(self, draw, start_pixel: list[int], message: str, font):
font_cls = LCD_FONT
if font == "CP437_FONT":
font_cls = CP437_FONT
text(draw, start_pixel, message, fill="white", font=proportional(font_cls))
def point(self, draw, pixel: list[int]):
draw.point(pixel, fill="white")
def line(self, draw, pixels: list[int], width):
if not width:
width=1
draw.line(pixels, fill="white", width=width)
def clear(self):
self.device.clear()
def reconfigure(self,
config: ComponentConfig,
dependencies: Mapping[ResourceName, ResourceBase]):
#Cleanup the screen and previous drawings on reconfigure
if self.device is not None:
self.device.cleanup()
spi_bus = int(config.attributes.fields["spi_bus"].string_value)
device = int(config.attributes.fields["device"].string_value)
block_orientation = int(config.attributes.fields["block_orientation"].number_value)
width = int(config.attributes.fields["width"].number_value)
height = int(config.attributes.fields["height"].number_value)
rotate = int(config.attributes.fields["rotate"].number_value)
self.serial = spi(port=spi_bus, device=device, gpio=noop())
self.device = max7219(self.serial, width=width, height=height, rotate=rotate, block_orientation=block_orientation)
@classmethod
def validate_config(self, config: ComponentConfig) -> None:
# Custom validation can be done by specifiying a validate function like this one. Validate functions
# can raise errors that will be returned to the parent through gRPC. Validate functions can
# also return a sequence of strings representing the implicit dependencies of the resource.
return None
if __name__ == '__main__':
# necessary for pyinstaller to see it
# build this with:
# pyinstaller --onefile --hidden-import viam-wrap --paths $VIRTUAL_ENV/lib/python3.10/site-packages installable.py
# `--paths` arg may no longer be necessary once viam-wrap is published somewhere
# todo: utility to append this stanza automatically at build time
viam_wrap.main(sys.modules.get(__name__))