bluer-sbc 8.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bluer-sbc might be problematic. Click here for more details.

Files changed (82) hide show
  1. bluer_sbc/.abcli/abcli.sh +12 -0
  2. bluer_sbc/.abcli/actions.sh +11 -0
  3. bluer_sbc/.abcli/adafruit_rgb_matrix.sh +14 -0
  4. bluer_sbc/.abcli/alias.sh +5 -0
  5. bluer_sbc/.abcli/blue_sbc.sh +11 -0
  6. bluer_sbc/.abcli/camera.sh +20 -0
  7. bluer_sbc/.abcli/grove.sh +43 -0
  8. bluer_sbc/.abcli/hat.sh +22 -0
  9. bluer_sbc/.abcli/install/adafruit_rgb_matrix.sh +15 -0
  10. bluer_sbc/.abcli/install/grove.sh +29 -0
  11. bluer_sbc/.abcli/install/lepton.sh +33 -0
  12. bluer_sbc/.abcli/install/rpi.sh +65 -0
  13. bluer_sbc/.abcli/install/scroll_phat_hd.sh +14 -0
  14. bluer_sbc/.abcli/install/sparkfun_top_phat.sh +33 -0
  15. bluer_sbc/.abcli/install/template.sh +9 -0
  16. bluer_sbc/.abcli/install/unicorn_16x16.sh +16 -0
  17. bluer_sbc/.abcli/lepton.sh +15 -0
  18. bluer_sbc/.abcli/scroll_phat_hd.sh +14 -0
  19. bluer_sbc/.abcli/session.sh +39 -0
  20. bluer_sbc/.abcli/sparkfun_top_phat.sh +27 -0
  21. bluer_sbc/.abcli/tests/README.sh +8 -0
  22. bluer_sbc/.abcli/tests/camera.sh +47 -0
  23. bluer_sbc/.abcli/tests/help.sh +65 -0
  24. bluer_sbc/.abcli/tests/version.sh +8 -0
  25. bluer_sbc/.abcli/unicorn_16x16.sh +14 -0
  26. bluer_sbc/README.py +51 -0
  27. bluer_sbc/__init__.py +17 -0
  28. bluer_sbc/__main__.py +16 -0
  29. bluer_sbc/algo/__init__.py +0 -0
  30. bluer_sbc/algo/diff.py +81 -0
  31. bluer_sbc/config.env +30 -0
  32. bluer_sbc/env.py +35 -0
  33. bluer_sbc/hardware/__init__.py +38 -0
  34. bluer_sbc/hardware/adafruit_rgb_matrix.py +30 -0
  35. bluer_sbc/hardware/display.py +112 -0
  36. bluer_sbc/hardware/grove.py +104 -0
  37. bluer_sbc/hardware/hardware.py +58 -0
  38. bluer_sbc/hardware/hat/__init__.py +0 -0
  39. bluer_sbc/hardware/hat/__main__.py +91 -0
  40. bluer_sbc/hardware/hat/abstract.py +136 -0
  41. bluer_sbc/hardware/hat/prototype.py +161 -0
  42. bluer_sbc/hardware/screen.py +17 -0
  43. bluer_sbc/hardware/scroll_phat_hd.py +35 -0
  44. bluer_sbc/hardware/sparkfun_top_phat/__init__.py +0 -0
  45. bluer_sbc/hardware/sparkfun_top_phat/__main__.py +51 -0
  46. bluer_sbc/hardware/sparkfun_top_phat/classes.py +104 -0
  47. bluer_sbc/hardware/unicorn_16x16.py +44 -0
  48. bluer_sbc/help/__init__.py +0 -0
  49. bluer_sbc/help/__main__.py +10 -0
  50. bluer_sbc/help/adafruit_rgb_matrix.py +23 -0
  51. bluer_sbc/help/camera.py +71 -0
  52. bluer_sbc/help/functions.py +52 -0
  53. bluer_sbc/help/grove.py +59 -0
  54. bluer_sbc/help/hat.py +56 -0
  55. bluer_sbc/help/lepton.py +39 -0
  56. bluer_sbc/help/scroll_phat_hd.py +23 -0
  57. bluer_sbc/help/session.py +26 -0
  58. bluer_sbc/help/sparkfun_top_phat.py +26 -0
  59. bluer_sbc/help/unicorn_16x16.py +23 -0
  60. bluer_sbc/host.py +11 -0
  61. bluer_sbc/imager/__init__.py +16 -0
  62. bluer_sbc/imager/camera/__init__.py +3 -0
  63. bluer_sbc/imager/camera/__main__.py +69 -0
  64. bluer_sbc/imager/camera/classes.py +259 -0
  65. bluer_sbc/imager/camera/constants.py +30 -0
  66. bluer_sbc/imager/classes.py +25 -0
  67. bluer_sbc/imager/lepton/__init__.py +3 -0
  68. bluer_sbc/imager/lepton/__main__.py +51 -0
  69. bluer_sbc/imager/lepton/classes.py +35 -0
  70. bluer_sbc/imager/lepton/python2.py +70 -0
  71. bluer_sbc/logger.py +5 -0
  72. bluer_sbc/sample.env +1 -0
  73. bluer_sbc/session/__init__.py +0 -0
  74. bluer_sbc/session/__main__.py +27 -0
  75. bluer_sbc/session/classes.py +318 -0
  76. bluer_sbc/session/functions.py +22 -0
  77. bluer_sbc/urls.py +1 -0
  78. bluer_sbc-8.3.1.dist-info/METADATA +58 -0
  79. bluer_sbc-8.3.1.dist-info/RECORD +82 -0
  80. bluer_sbc-8.3.1.dist-info/WHEEL +5 -0
  81. bluer_sbc-8.3.1.dist-info/licenses/LICENSE +121 -0
  82. bluer_sbc-8.3.1.dist-info/top_level.txt +1 -0
bluer_sbc/__init__.py ADDED
@@ -0,0 +1,17 @@
1
+ NAME = "bluer_sbc"
2
+
3
+ ICON = "🌀"
4
+
5
+ DESCRIPTION = f"{ICON} AI for single board computers."
6
+
7
+ VERSION = "8.3.1"
8
+
9
+ REPO_NAME = "bluer-sbc"
10
+
11
+ MARQUEE = "https://github.com/kamangir/blue-bracket/blob/main/images/helmet-3.jpg"
12
+
13
+ ALIAS = "@sbc"
14
+
15
+
16
+ def fullname() -> str:
17
+ return f"{NAME}-{VERSION}"
bluer_sbc/__main__.py ADDED
@@ -0,0 +1,16 @@
1
+ from blueness.argparse.generic import main
2
+
3
+ from bluer_sbc import NAME, VERSION, DESCRIPTION, ICON, README
4
+ from bluer_sbc.logger import logger
5
+
6
+ main(
7
+ ICON=ICON,
8
+ NAME=NAME,
9
+ DESCRIPTION=DESCRIPTION,
10
+ VERSION=VERSION,
11
+ main_filename=__file__,
12
+ tasks={
13
+ "build_README": lambda _: README.build(),
14
+ },
15
+ logger=logger,
16
+ )
File without changes
bluer_sbc/algo/diff.py ADDED
@@ -0,0 +1,81 @@
1
+ import cv2
2
+ import numpy as np
3
+ import time
4
+
5
+ from blueness import module
6
+ from bluer_options import string
7
+ from bluer_options.logger import crash_report
8
+
9
+ from bluer_sbc import NAME
10
+ from bluer_sbc.logger import logger
11
+
12
+ NAME = module.name(__file__, NAME)
13
+
14
+
15
+ class Diff:
16
+ def __init__(self, threshold=0.1):
17
+ self.size = (60, 80)
18
+ self.threshold = threshold
19
+
20
+ self.last_diff = 0.0
21
+ self.last_same_period = 0.0
22
+ self.last_diff_time = time.time()
23
+
24
+ self.previous = None
25
+
26
+ def same(self, image):
27
+ if self.threshold < 0:
28
+ return False
29
+
30
+ image_scaled = cv2.resize(image, self.size)
31
+
32
+ if self.previous is None:
33
+ self.previous = image_scaled
34
+ self.last_diff_time = time.time()
35
+
36
+ logger.info(
37
+ f"{NAME}.diff.same({string.pretty_shape_of_matrix(image)}): initialized."
38
+ )
39
+ return False
40
+
41
+ try:
42
+ self.last_diff = float(
43
+ np.percentile(
44
+ np.abs(
45
+ image_scaled.astype(np.float) - self.previous.astype(np.float)
46
+ ),
47
+ 90,
48
+ )
49
+ / 255
50
+ )
51
+ is_same = self.last_diff <= self.threshold
52
+
53
+ logger.info(
54
+ "{}.diff.same({}): {:.03f} - {}{}".format(
55
+ NAME,
56
+ string.pretty_shape_of_matrix(image),
57
+ self.last_diff,
58
+ ("!same,same".split(","))[int(is_same)],
59
+ " - {} since last diff.".format(
60
+ string.pretty_duration(
61
+ time.time() - self.last_diff_time,
62
+ include_ms=True,
63
+ largest=True,
64
+ short=True,
65
+ )
66
+ ),
67
+ )
68
+ )
69
+
70
+ if not is_same:
71
+ self.last_same_period = time.time() - self.last_diff_time
72
+ self.last_diff_time = time.time()
73
+
74
+ self.previous = image_scaled
75
+
76
+ return is_same
77
+ except Exception as e:
78
+ crash_report(e)
79
+
80
+ self.previous = None
81
+ return False
bluer_sbc/config.env ADDED
@@ -0,0 +1,30 @@
1
+ BLUER_SBC_CAMERA_HI_RES=1
2
+ BLUER_SBC_CAMERA_WIDTH=728
3
+ BLUER_SBC_CAMERA_HEIGHT=600
4
+ BLUER_SBC_CAMERA_ROTATION=0
5
+
6
+ BLUER_SBC_DISPLAY_FULLSCREEN=1
7
+
8
+ BLUER_SBC_HARDWARE_KIND=other
9
+
10
+ BLUER_SBC_SESSION_OBJECT_TAGS=validation
11
+
12
+ BLUER_SBC_SESSION_PLUGIN=bluer_sbc
13
+
14
+ BLUER_SBC_SESSION_IMAGER=other
15
+
16
+ BLUER_SBC_SESSION_IMAGER_DIFF=0.1
17
+ BLUER_SBC_SESSION_IMAGER_ENABLED=1
18
+
19
+ BLUER_SBC_SESSION_MONITOR_ENABLED=1
20
+
21
+
22
+ BLUER_SBC_SESSION_OUTBOUND_QUEUE=stream
23
+
24
+ BLUER_SBC_SESSION_AUTO_UPLOAD=1
25
+
26
+ BLUER_SBC_SESSION_IMAGER_PERIOD=300
27
+ BLUER_SBC_SESSION_MESSENGER_PERIOD=60
28
+ BLUER_SBC_SESSION_REBOOT_PERIOD=14400
29
+ BLUER_SBC_SESSION_SCREEN_PERIOD=4
30
+ BLUER_SBC_SESSION_TEMPERATURE_PERIOD=300
bluer_sbc/env.py ADDED
@@ -0,0 +1,35 @@
1
+ from bluer_options.env import load_config, load_env, get_env
2
+
3
+ load_config(__name__)
4
+ load_env(__name__)
5
+
6
+ BLUER_SBC_CAMERA_HI_RES = get_env("BLUER_SBC_CAMERA_HI_RES", True)
7
+ BLUER_SBC_CAMERA_WIDTH = get_env("BLUER_SBC_CAMERA_WIDTH", 728)
8
+ BLUER_SBC_CAMERA_HEIGHT = get_env("BLUER_SBC_CAMERA_HEIGHT", 600)
9
+ BLUER_SBC_CAMERA_ROTATION = get_env("BLUER_SBC_CAMERA_ROTATION", 0)
10
+
11
+ BLUER_SBC_DISPLAY_FULLSCREEN = get_env("BLUER_SBC_DISPLAY_FULLSCREEN", True)
12
+
13
+ BLUER_SBC_HARDWARE_KIND = get_env("BLUER_SBC_HARDWARE_KIND")
14
+
15
+ BLUER_SBC_SESSION_PLUGIN = get_env("BLUER_SBC_SESSION_PLUGIN")
16
+
17
+ BLUER_SBC_SESSION_IMAGER = get_env("BLUER_SBC_SESSION_IMAGER")
18
+ BLUER_SBC_SESSION_IMAGER_DIFF = get_env("BLUER_SBC_SESSION_IMAGER_DIFF", 0.1)
19
+ BLUER_SBC_SESSION_IMAGER_ENABLED = get_env("BLUER_SBC_SESSION_IMAGER_ENABLED", True)
20
+
21
+ BLUER_SBC_SESSION_MONITOR_ENABLED = get_env("BLUER_SBC_SESSION_MONITOR_ENABLED", True)
22
+
23
+ BLUER_SBC_SESSION_OBJECT_TAGS = get_env("BLUER_SBC_SESSION_OBJECT_TAGS")
24
+
25
+ BLUER_SBC_SESSION_OUTBOUND_QUEUE = get_env("BLUER_SBC_SESSION_OUTBOUND_QUEUE")
26
+
27
+ BLUER_SBC_SESSION_AUTO_UPLOAD = get_env("BLUER_SBC_SESSION_AUTO_UPLOAD", True)
28
+
29
+ BLUER_SBC_SESSION_IMAGER_PERIOD = get_env("BLUER_SBC_SESSION_IMAGER_PERIOD", 300)
30
+ BLUER_SBC_SESSION_MESSENGER_PERIOD = get_env("BLUER_SBC_SESSION_MESSENGER_PERIOD", 60)
31
+ BLUER_SBC_SESSION_REBOOT_PERIOD = get_env("BLUER_SBC_SESSION_REBOOT_PERIOD", 14400)
32
+ BLUER_SBC_SESSION_SCREEN_PERIOD = get_env("BLUER_SBC_SESSION_SCREEN_PERIOD", 4)
33
+ BLUER_SBC_SESSION_TEMPERATURE_PERIOD = get_env(
34
+ "BLUER_SBC_SESSION_TEMPERATURE_PERIOD", 300
35
+ )
@@ -0,0 +1,38 @@
1
+ from blueness import module
2
+ from bluer_options import host
3
+
4
+ from bluer_sbc import NAME
5
+ from bluer_sbc.env import BLUER_SBC_HARDWARE_KIND
6
+ from bluer_sbc.hardware.hardware import Hardware as Hardware_Class
7
+ from bluer_sbc.logger import logger
8
+
9
+ NAME = module.name(__file__, NAME)
10
+
11
+
12
+ if host.is_mac():
13
+ from bluer_sbc.hardware.display import Display as Hardware_Class
14
+ elif BLUER_SBC_HARDWARE_KIND == "adafruit_rgb_matrix":
15
+ from bluer_sbc.hardware.adafruit_rgb_matrix import (
16
+ Adafruit_Rgb_Matrix as Hardware_Class,
17
+ )
18
+ elif BLUER_SBC_HARDWARE_KIND == "grove":
19
+ from bluer_sbc.hardware.grove import Grove as Hardware_Class
20
+ elif BLUER_SBC_HARDWARE_KIND == "prototype_hat":
21
+ if host.is_headless():
22
+ from bluer_sbc.hardware.hat.prototype import Prototype_Hat as Hardware_Class
23
+ else:
24
+ from bluer_sbc.hardware.display import Display as Hardware_Class
25
+ elif BLUER_SBC_HARDWARE_KIND == "scroll_phat_hd":
26
+ from bluer_sbc.hardware.scroll_phat_hd import Scroll_Phat_HD as Hardware_Class
27
+ elif BLUER_SBC_HARDWARE_KIND == "sparkfun-top-phat":
28
+ from bluer_sbc.hardware.sparkfun_top_phat.classes import (
29
+ Sparkfun_Top_phat as Hardware_Class,
30
+ )
31
+ elif BLUER_SBC_HARDWARE_KIND == "unicorn_16x16":
32
+ from bluer_sbc.hardware.unicorn_16x16 import Unicorn_16x16 as Hardware_Class
33
+ else:
34
+ raise NameError(f"bluer-sbc: {BLUER_SBC_HARDWARE_KIND}: hardware not found.")
35
+
36
+ hardware = Hardware_Class()
37
+
38
+ logger.info(f"{NAME}: {BLUER_SBC_HARDWARE_KIND}: {hardware.__class__.__name__}")
@@ -0,0 +1,30 @@
1
+ import cv2
2
+ from PIL import Image
3
+
4
+ from bluer_sbc.hardware.screen import Screen
5
+
6
+
7
+ class Adafruit_Rgb_Matrix(Screen):
8
+ def __init__(self):
9
+ super(Adafruit_Rgb_Matrix, self).__init__()
10
+ self.size = (32, 32)
11
+ self.animated = True
12
+
13
+ from rgbmatrix import RGBMatrix, RGBMatrixOptions
14
+
15
+ options = RGBMatrixOptions()
16
+ options.rows = 32
17
+ options.chain_length = 1
18
+ options.parallel = 1
19
+ options.hardware_mapping = "adafruit-hat" # adafruit-hat/regular
20
+
21
+ self.matrix = RGBMatrix(options=options)
22
+
23
+ def update_screen(self, image, session, header):
24
+ image = cv2.resize(image, self.size)
25
+
26
+ super().update_screen(image, session, header)
27
+
28
+ self.matrix.SetImage(Image.fromarray(image).convert("RGB"))
29
+
30
+ return self
@@ -0,0 +1,112 @@
1
+ import cv2
2
+ import numpy as np
3
+
4
+ from blueness import module
5
+ from bluer_options.logger import crash_report
6
+ from bluer_options.host import is_mac
7
+ from bluer_objects import file
8
+ from bluer_objects.graphics import add_signature
9
+ from bluer_objects.graphics.screen import get_size
10
+
11
+ from bluer_sbc import NAME
12
+ from bluer_sbc import env
13
+ from bluer_sbc.hardware.hat.prototype import Prototype_Hat
14
+ from bluer_sbc.host import signature
15
+ from bluer_sbc.logger import logger
16
+
17
+
18
+ NAME = module.name(__file__, NAME)
19
+
20
+
21
+ class Display(Prototype_Hat):
22
+ def __init__(self):
23
+ super().__init__()
24
+
25
+ self.canvas = None
26
+ self.canvas_size = (640, 480)
27
+
28
+ self.title = " | ".join(signature())
29
+
30
+ self.created = False
31
+
32
+ self.sign_images = True
33
+ self.interpolation = cv2.INTER_LINEAR
34
+
35
+ def create(self):
36
+ if self.created:
37
+ return
38
+ self.created = True
39
+
40
+ logger.info(f"{NAME}.create()")
41
+
42
+ if env.BLUER_SBC_DISPLAY_FULLSCREEN and not is_mac():
43
+ # https://stackoverflow.com/a/34337534
44
+ cv2.namedWindow(self.title, cv2.WND_PROP_FULLSCREEN)
45
+ cv2.setWindowProperty(
46
+ self.title, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN
47
+ )
48
+
49
+ screen_height, screen_width = get_size()
50
+ self.canvas_size = (
51
+ screen_width,
52
+ screen_height,
53
+ )
54
+ else:
55
+ cv2.namedWindow(self.title, cv2.WINDOW_NORMAL)
56
+ cv2.resizeWindow(
57
+ self.title,
58
+ self.canvas_size[0],
59
+ self.canvas_size[1],
60
+ )
61
+
62
+ def save(self, filename: str = "") -> str:
63
+ if self.canvas is None:
64
+ return ""
65
+
66
+ if not filename:
67
+ filename = file.auxiliary("display", "jpg")
68
+
69
+ return filename if file.save_image(filename, self.canvas) else ""
70
+
71
+ def update_gui(self):
72
+ try:
73
+ if len(self.canvas.shape) == 2:
74
+ self.canvas = np.stack(3 * [self.canvas], axis=2)
75
+
76
+ cv2.imshow(
77
+ self.title,
78
+ cv2.cvtColor(
79
+ cv2.resize(
80
+ self.canvas,
81
+ dsize=self.canvas_size,
82
+ interpolation=self.interpolation,
83
+ ),
84
+ cv2.COLOR_BGR2RGB,
85
+ ),
86
+ )
87
+ except Exception as e:
88
+ crash_report(e)
89
+
90
+ def update_screen(self, image, session, header):
91
+ super().update_screen(image, session, header)
92
+
93
+ self.canvas = np.copy(image)
94
+
95
+ if self.sign_images:
96
+ self.canvas = add_signature(
97
+ self.canvas,
98
+ header=header,
99
+ footer=[" | ".join(signature())],
100
+ )
101
+
102
+ self.create()
103
+
104
+ self.update_gui()
105
+
106
+ key = cv2.waitKey(1)
107
+ if key not in [-1, 255]:
108
+ key = chr(key).lower()
109
+ logger.info(f"{NAME}.update_screen(): key: '{key}'")
110
+ self.key_buffer.append(key)
111
+
112
+ return self
@@ -0,0 +1,104 @@
1
+ from PIL import Image
2
+ from PIL import ImageDraw
3
+ from PIL import ImageFont
4
+
5
+ from bluer_options import string
6
+
7
+ from bluer_sbc.hardware.screen import Screen
8
+ from bluer_sbc.logger import logger
9
+
10
+ BUTTON = 24
11
+
12
+ RST = None # on the PiOLED this pin isnt used
13
+
14
+
15
+ class Grove(Screen):
16
+ def __init__(self):
17
+ super(Grove, self).__init__()
18
+
19
+ from grove.grove_button import GroveButton
20
+
21
+ # https://wiki.seeedstudio.com/Grove-OLED_Display_0.96inch/
22
+ self.size = (64, 128)
23
+
24
+ self.button = GroveButton(BUTTON)
25
+ self.button.on_press = lambda t: grove_button_on_press(self, t)
26
+ self.button.on_release = lambda t: grove_button_on_release(self, t)
27
+
28
+ import Adafruit_SSD1306
29
+
30
+ # https://github.com/IcingTomato/Seeed_Python_SSD1315/blob/master/examples/stats.py
31
+ self.display = Adafruit_SSD1306.SSD1306_128_64(rst=RST)
32
+
33
+ self.display.begin()
34
+ self.display.clear()
35
+ self.display.display()
36
+
37
+ self.image = Image.new(
38
+ "1",
39
+ (self.display.width, self.display.height),
40
+ )
41
+
42
+ self.draw = ImageDraw.Draw(self.image)
43
+
44
+ # Draw a black filled box to clear the image.
45
+ self.draw.rectangle(
46
+ (0, 0, self.display.width, self.display.height),
47
+ outline=0,
48
+ fill=0,
49
+ )
50
+
51
+ self.padding = -2
52
+ self.top = self.padding
53
+ self.bottom = self.display.height - self.padding
54
+
55
+ self.font = ImageFont.load_default()
56
+
57
+ self.line_count = 8
58
+ self.line_length = 21
59
+
60
+ def update_screen(self, image, session, header):
61
+ super().update_screen(image, session, header)
62
+
63
+ signature = (" | ".join(session.signature())).split(" | ")
64
+
65
+ self.draw.rectangle(
66
+ (0, 0, self.display.width, self.display.height),
67
+ outline=0,
68
+ fill=0,
69
+ )
70
+
71
+ for row in range(min(len(signature), self.line_count)):
72
+ self.draw.text(
73
+ (0, self.top + 8 * row),
74
+ signature[row],
75
+ font=self.font,
76
+ fill=255,
77
+ )
78
+
79
+ self.display.image(self.image)
80
+ self.display.display()
81
+
82
+ return self
83
+
84
+
85
+ def grove_button_on_press(screen: Screen, t):
86
+ logger.info("grove.button: pressed.")
87
+
88
+
89
+ def grove_button_on_release(screen: Screen, t):
90
+ logger.info(f"grove.button: released after {string.pretty_duration(t)}.")
91
+
92
+ if t > 60:
93
+ logger.info("long press, ignored.")
94
+ return
95
+
96
+ if t > 5:
97
+ key = "s"
98
+ elif t > 3:
99
+ key = "u"
100
+ else:
101
+ key = " "
102
+
103
+ screen.key_buffer.append(key)
104
+ logger.info(f"{screen.__class__.__name__}: '{key}'")
@@ -0,0 +1,58 @@
1
+ import random
2
+
3
+ from bluer_sbc import fullname
4
+ from bluer_sbc.logger import logger
5
+
6
+
7
+ class Hardware:
8
+ def __init__(self):
9
+ logger.info(f"{self.__class__.__name__}.init().")
10
+
11
+ self.key_buffer = []
12
+ self.animated = False
13
+
14
+ def animate(self):
15
+ if self.buffer is None:
16
+ return self
17
+ if not self.animated:
18
+ return self
19
+
20
+ y = random.randint(0, self.buffer.shape[0] - 1)
21
+ x = random.randint(0, self.buffer.shape[1] - 1)
22
+
23
+ self.buffer[y, x] = 255 - self.buffer[y, x]
24
+
25
+ self.animated = False
26
+ self.update_screen(self.buffer, None, [], [])
27
+ self.animated = True
28
+
29
+ def clock(self):
30
+ return self
31
+
32
+ def pressed(self, keys):
33
+ output = bool([key for key in keys if key in self.key_buffer])
34
+
35
+ self.key_buffer = [key for key in self.key_buffer if key not in keys]
36
+
37
+ return output
38
+
39
+ def pulse(self, pin=None, frequency=None):
40
+ """
41
+ pulse pin.
42
+ :param pin: "data" / "incoming" / "loop" / "outputs"
43
+ :param frequency: frequency
44
+ :return: self
45
+ """
46
+ return self
47
+
48
+ def release(self):
49
+ logger.info(f"{self.__class__.__name__}.release()")
50
+
51
+ def signature(self):
52
+ return [
53
+ fullname(),
54
+ f"hardware:{self.__class__.__name__}",
55
+ ]
56
+
57
+ def update_screen(self, image, session, header):
58
+ return self
File without changes
@@ -0,0 +1,91 @@
1
+ import argparse
2
+ import time
3
+
4
+ from blueness import module
5
+ from bluer_options import string
6
+
7
+ from bluer_sbc import NAME
8
+ from bluer_sbc.hardware.hat.prototype import Prototype_Hat
9
+ from bluer_sbc.logger import logger
10
+
11
+ NAME = module.name(__file__, NAME)
12
+
13
+
14
+ parser = argparse.ArgumentParser(NAME)
15
+ parser.add_argument(
16
+ "task",
17
+ type=str,
18
+ default="",
19
+ help="input/output",
20
+ )
21
+ parser.add_argument(
22
+ "--outputs",
23
+ type=str,
24
+ default="",
25
+ )
26
+ args = parser.parse_args()
27
+
28
+ hardware = Prototype_Hat()
29
+
30
+ success = False
31
+ if args.task == "input":
32
+ logger.info("loop started (Ctrl+C to stop)")
33
+ # https://stackoverflow.com/a/18994932/10917551
34
+ try:
35
+ while True:
36
+ logger.info(
37
+ "inputs: {}".format(
38
+ ", ".join([str(hardware.input(pin)) for pin in hardware.input_pins])
39
+ )
40
+ )
41
+ time.sleep(0.1)
42
+ except KeyboardInterrupt:
43
+ logger.info("Ctrl+C, stopping.")
44
+ finally:
45
+ hardware.release()
46
+ success = True
47
+ elif args.task == "output":
48
+ outputs = args.outputs + len(hardware.output_pins) * "1"
49
+ for index, pin in enumerate(hardware.output_pins):
50
+ hardware.output(pin, outputs[index] == "1")
51
+ hardware.release()
52
+ success = True
53
+ elif args.task == "validate":
54
+ logger.info("loop started (Ctrl+C to stop)")
55
+ value = True
56
+ try:
57
+ while True:
58
+ activity = False
59
+ for pin, pin_name in zip(
60
+ [
61
+ hardware.green_switch_pin,
62
+ hardware.red_switch_pin,
63
+ hardware.switch_pin,
64
+ hardware.trigger_pin,
65
+ ],
66
+ "green_switch_pin,red_switch_pin,switch_pin,trigger_pin".split(","),
67
+ ):
68
+ if hardware.activated(pin):
69
+ logger.info(
70
+ "{}: {} activated.".format(
71
+ string.timestamp(ms=True),
72
+ pin_name,
73
+ )
74
+ )
75
+ activity = True
76
+
77
+ for pin in hardware.output_pins:
78
+ hardware.output(pin, activity or value)
79
+ time.sleep(0.1)
80
+
81
+ value = not value
82
+ except KeyboardInterrupt:
83
+ logger.info("Ctrl+C, stopping.")
84
+ finally:
85
+ hardware.release()
86
+ success = True
87
+ else:
88
+ logger.error(f"-{NAME}: {args.task}: command not found.")
89
+
90
+ if not success:
91
+ logger.error(f"-{NAME}: {args.task}: failed.")