-
Notifications
You must be signed in to change notification settings - Fork 7
/
main.py
executable file
·202 lines (184 loc) · 5.79 KB
/
main.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#!/usr/bin/env python
#
# This is a project to drive a 32x8 or 16x16 LED matrix based on the popular
# WS2812 RGB LEDs using a microcontroller running MicroPython (preferrably
# one with 4MB RAM although modules with 1MB also work).
#
# -- [email protected], 2018
#
import sys
import time
import gc
from math import ceil
from ledmatrix import LedMatrix
# This is to make sure we have a large contiguous block of RAM on devices with
# 520kB RAM after all modules and modules have been compiled and instantiated.
#
# In the weather scene, the ussl module needs a large chunk of around 1850
# bytes, and without the dummy allocation below the heap will be too
# fragmented after all the initial processing to find such a large chunk.
large_temp_chunk = bytearray(3400)
pycom_board = False
esp8266_board = False
if hasattr(sys,'implementation') and sys.implementation.name == 'micropython':
import ujson as json
import machine
from network import WLAN
from os import uname
tmp = uname()
if tmp.sysname == 'esp8266':
esp8266_board = True
from upyhal import uPyHAL as HAL
else:
pycom_board = True
from pycomhal import PycomHAL as HAL
tmp = None
del uname
else:
import json
import os
import signal
# Kludge to allow this project to be used with a Raspberry Pi instead of
# an MCU: see https://github.com/noahwilliamsson/lamatrix/issues/1
try:
# If the rpi_ws281x Python module is available, then use that...
from raspberrypihal import RaspberryPiHAL as HAL
except:
# ...else assume that there's an MCU (driving the display) connected
# to a serial port
from arduinoserialhal import ArduinoSerialHAL as HAL
gc.collect()
from renderloop import RenderLoop
def sigint_handler(sig, frame):
"""
Clear display when the program is terminated by Ctrl-C or SIGTERM
"""
global driver
driver.clear_display()
driver.set_auto_time(True)
sys.exit(0)
if __name__ == '__main__':
f = open('config.json')
config = json.loads(f.read())
f.close()
del json
# Initialize HAL
driver = HAL(config)
if not esp8266_board and not pycom_board:
# We're running on the host computer here
ports = [
'/dev/tty.usbmodem575711', # Teensy 3.x on macOS
'/dev/tty.usbserial-DQ008J7R', # Pycom device on macOS
'/dev/ttyUSB0', # Linux
'/dev/ttyACM0', # Linux
]
for port in ports:
if os.path.exists(port):
config['port'] = port
break
# Disable automatic rendering of time
driver.set_auto_time(False)
# Trap Ctrl-C and service termination
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTERM, sigint_handler)
# Initialize led matrix framebuffer on top of HAL
display = LedMatrix(driver, config['LedMatrix'])
driver.clear_display()
if pycom_board:
# We're running under MCU here
from bootscene import BootScene
scene = BootScene(display, config['Boot'])
wlan = WLAN(mode=WLAN.STA)
if not wlan.isconnected():
print('WLAN: Scanning for networks')
scene.render(0,0,0)
default_ssid, default_auth = wlan.ssid(), wlan.auth()
candidates = wlan.scan()
for conf in config['networks']:
nets = [candidate for candidate in candidates if candidate.ssid == conf['ssid']]
if not nets:
continue
print('WLAN: Connecting to known network: {}'.format(nets[0].ssid))
wlan.connect(nets[0].ssid, auth=(nets[0].sec, conf['password']))
for i in range(1,40):
scene.render(i, 0, 0)
time.sleep(0.2)
if wlan.isconnected():
break
if wlan.isconnected():
break
scene.render(0, 0, 0)
if not wlan.isconnected():
# TODO: This will only use SSID/auth settings from NVRAM during cold boots
print('WLAN: No known networks, enabling AP with ssid={}, pwd={}'.format(default_ssid, default_auth[1]))
wlan.init(mode=WLAN.AP, ssid=default_ssid, auth=default_auth, channel=6)
else:
display.clear()
print('WLAN: Connected with IP: {}'.format(wlan.ifconfig()[0]))
# Initialize RTC now that we're connected
driver.set_rtc(scene)
scene.render(0,0,0)
scene = None
del BootScene
elif esp8266_board:
pass
# This is where it all begins
r = RenderLoop(display, config)
if 'Clock' in config:
from clockscene import ClockScene
scene = ClockScene(display, config['Clock'])
r.add_scene(scene)
gc.collect()
if 'Demo' in config:
from demoscene import DemoScene
scene = DemoScene(display, config['Demo'])
r.add_scene(scene)
gc.collect()
if 'Weather' in config:
from weatherscene import WeatherScene
scene = WeatherScene(display, config['Weather'])
r.add_scene(scene)
gc.collect()
if 'Fire' in config:
from firescene import FireScene
scene = FireScene(display, config['Fire'])
r.add_scene(scene)
gc.collect()
if 'Animation' in config:
from animationscene import AnimationScene
scene = AnimationScene(display, config['Animation'])
r.add_scene(scene)
gc.collect()
# Now that we're all setup, release the large chunk
large_temp_chunk = None
# Render scenes forever
while True:
# Process input
button_state = 0
if pycom_board:
# When running under MicroPython on the MCU we need to deal with
# any input coming from the host over the serial link
while True:
button_state = driver.process_input()
if driver.enable_auto_time:
# If the host disconnected we'll hand over control to the
# game loop which will take care of updating the display
break
else:
# When running under regular Python on the host computer we need
# to pick up any button presses sent over the serial link from
# the Arduino firmware
n = 0
while True:
# Drain output from MCU and detect button presses
line = driver.process_input()
if not line:
break
event = line.strip()
if event == 'LEFTB_SHRT_PRESS':
button_state = 1
elif event == 'LEFTB_LONG_PRESS':
button_state = 2
else:
print('MCU: {}'.format(event))
r.next_frame(button_state)