Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Rainbow pattern #8

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
41 changes: 41 additions & 0 deletions Dockerfiles/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
FROM python:3.9.4-alpine

ENV PACKAGES="\
alsa-plugins \
alsa-plugins-a52 \
alsa-plugins-jack \
alsa-plugins-lavrate \
alsa-plugins-pulse \
bash \
git \
libc6-compat \
libgfortran \
libstdc++ \
openblas \
portaudio \
"

ENV PYTHON_PACKAGES="\
gpiozero \
numpy \
pigpio \
pyaudio \
spidev \
wave \
"

RUN apk add --virtual build-deps build-base openblas-dev freetype-dev pkgconfig gfortran linux-headers portaudio-dev \
&& ln -s /usr/include/locale.h /usr/include/xlocale.h \
&& pip install --no-cache-dir $PYTHON_PACKAGES \
&& apk del build-deps \
&& apk add --no-cache --virtual build-runtime $PACKAGES \
&& rm -rf /var/cache/apk/*

WORKDIR /usr/src/app

RUN git clone https://github.com/lavirott/4mics_hat

WORKDIR /usr/src/app/4mics_hat

ENTRYPOINT ["python3"]
CMD ["pixels_demo.py"]
11 changes: 11 additions & 0 deletions Dockerfiles/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
4MICs HAT for Raspberry Pi
========================

## Docker
To build the docker image, you need to upgrade the libseccomp2 library (bug identified in 12/2020)

1. wget http://ftp.fr.debian.org/debian/pool/main/libs/libseccomp/libseccomp2_2.5.1-1_armhf.deb
2. wget http://ftp.fr.debian.org/debian/pool/main/libs/libseccomp/libseccomp-dev_2.5.1-1_armhf.deb
3. sudo dpkg -i libseccomp2_2.5.1-1_armhf.deb libseccomp-dev_2.5.1-1_armhf.deb
4. rm *.deb
5. docker-docker-compose build
13 changes: 13 additions & 0 deletions Dockerfiles/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "3"
services:
respeaker:
image: lavirott/respeaker:latest
container_name: respeaker
build: .
devices:
- /dev/spidev0.1:/dev/spidev0.1
- /dev/gpiomem:/dev/gpiomem
- /dev/snd:/dev/snd
volumes:
- /usr/share/alsa:/usr/share/alsa
- /etc/alsa:/etc/alsa
19 changes: 10 additions & 9 deletions alexa_led_pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@


class AlexaLedPattern(object):
def __init__(self, show=None, number=12):
self.pixels_number = number
self.pixels = [0] * 4 * number
def __init__(self, show=None, num_led=12):
self.num_led = num_led
self.pixels = [0] * 4 * num_led

if not show or not callable(show):
def dummy(data):
Expand All @@ -33,20 +33,21 @@ def dummy(data):
self.stop = False

def wakeup(self, direction=0):
position = int((direction + 15) / (360 / self.pixels_number)) % self.pixels_number
position = int((direction + 15) / (360 / self.num_led)) % self.num_led

pixels = [0, 0, 0, 24] * self.pixels_number
pixels = [0, 0, 0, 24] * self.num_led
pixels[position * 4 + 2] = 48

print(pixels)
print(position)
self.show(pixels)

def listen(self):
pixels = [0, 0, 0, 24] * self.pixels_number
pixels = [0, 0, 0, 24] * self.num_led

self.show(pixels)

def think(self):
pixels = [0, 0, 12, 12, 0, 0, 0, 24] * self.pixels_number
pixels = [0, 0, 12, 12, 0, 0, 0, 24] * self.num_led

while not self.stop:
self.show(pixels)
Expand All @@ -57,7 +58,7 @@ def speak(self):
step = 1
position = 12
while not self.stop:
pixels = [0, 0, position, 24 - position] * self.pixels_number
pixels = [0, 0, position, 24 - position] * self.num_led
self.show(pixels)
time.sleep(0.01)
if position <= 0:
Expand Down
7 changes: 4 additions & 3 deletions google_home_led_pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@


class GoogleHomeLedPattern(object):
def __init__(self, show=None):
def __init__(self, show=None, num_led=12):
self.num_led = num_led
self.basis = numpy.array([0] * 4 * 12)
self.basis[0 * 4 + 1] = 2
self.basis[3 * 4 + 1] = 1
Expand All @@ -43,7 +44,7 @@ def dummy(data):
self.stop = False

def wakeup(self, direction=0):
position = int((direction + 15) / 30) % 12
position = int((direction + 15) / 30) % self.num_led

basis = numpy.roll(self.basis, position * 4)
for i in range(1, 25):
Expand Down Expand Up @@ -105,6 +106,6 @@ def speak(self):
brightness += step

def off(self):
self.show([0] * 4 * 12)
self.show([0] * 4 * self.num_led)


22 changes: 18 additions & 4 deletions pixels_demo.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import signal
import sys
import time
from pixels import Pixels, pixels
from alexa_led_pattern import AlexaLedPattern
from google_home_led_pattern import GoogleHomeLedPattern
from rainbow_led_pattern import RainbowLedPattern

if __name__ == '__main__':
global pixels

pixels.pattern = GoogleHomeLedPattern(show=pixels.show)
class GracefulKiller:
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)

while True:
def exit_gracefully(self,signum, frame):
global pixels
pixels.off()
sys.exit(0)

if __name__ == '__main__':
global pixels
pixels.pattern = RainbowLedPattern(show=pixels.show)
killer = GracefulKiller()

while True:
try:
pixels.wakeup()
time.sleep(3)
Expand All @@ -21,6 +36,5 @@
except KeyboardInterrupt:
break


pixels.off()
time.sleep(1)
91 changes: 91 additions & 0 deletions rainbow_led_pattern.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env python

# Copyright (C) 2017 Seeed Technology Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import numpy
import time
import colorsys

def hsv2rgb(h,s,v):
return tuple(round(i * 255) for i in colorsys.hsv_to_rgb(h,s,v))

class RainbowLedPattern(object):
def __init__(self, show=None, num_led=12):
self.num_led = num_led

jump = 1.0 / (self.num_led * 1.0)
pixels = numpy.array([0.0] * 4 * self.num_led)
for i in range(self.num_led):
color = [jump * i, 0.5, 0.5]
for j in range(3):
pixels[(i * 4) + j + 1] = color[j]
self.pixels = pixels

if not show or not callable(show):
def dummy(data):
pass
show = dummy

self.show = show
self.stop = False

def convert_to_rgb(self, pixels_hsv):
pixels_rgb = numpy.copy(pixels_hsv)
for i in range(self.num_led):
color_rgb = hsv2rgb(pixels_hsv[(i*4)+1], pixels_hsv[(i*4)+2], pixels_hsv[(i*4)+3])
for j in range(3):
pixels_rgb[(i*4)+j+1] = color_rgb[j]
return pixels_rgb

def wakeup(self, direction=0):
position = int((direction + 15) / (360 / self.num_led)) % self.num_led
pixels = self.convert_to_rgb(self.pixels)
self.show(pixels)

def listen(self):
self.show(self.pixels)

def think(self):
pixels = self.convert_to_rgb(self.pixels)
while not self.stop:
self.show(pixels)
time.sleep(0.2)
pixels = numpy.roll(pixels, 4)

def change_sv(self, pixels_hsv, incr):
pixels = numpy.copy(pixels_hsv)
for i in range(self.num_led):
pixels[(i*4)+2] += incr
pixels[(i*4)+3] += incr
return pixels

def speak(self):
pixels_hsv = numpy.copy(self.pixels)
step = 0.025
while not self.stop:
pixels_hsv = self.change_sv(pixels_hsv, step)
pixels_rgb = self.convert_to_rgb(pixels_hsv)
self.show(pixels_rgb)
time.sleep(0.1)
if pixels_hsv[2] <= 0.5:
step = 0.1
time.sleep(0.4)
elif pixels_hsv[2] >= 0.8:
step = -0.1
time.sleep(0.4)

def off(self):
self.show([0] * 4 * self.num_led)