From 5cb309a9bb3481534b353cb50c707a64b4155c00 Mon Sep 17 00:00:00 2001 From: Jakob Stendahl Date: Thu, 18 Oct 2018 12:41:52 +0200 Subject: :construction: Work on installer and making the supportfiles do led control --- app.js | 7 +- bin/install.sh | 77 ++++------ .../pythonSupportFiles/LuxcenaNeo/Strip.py | 163 ++++++++++++++++++++- src/compileAndRun/pythonSupportFiles/entry.py | 4 +- 4 files changed, 192 insertions(+), 59 deletions(-) diff --git a/app.js b/app.js index 01f7242..406ecbd 100644 --- a/app.js +++ b/app.js @@ -63,7 +63,12 @@ if (!fse.existsSync(dataDir + "/config/versionChecker.json")) { if (!fse.existsSync(dataDir + "/config/strip.json")) { fse.writeJsonSync(dataDir + "/config/strip.json", { "segments": [9, 8, 8, 8, 8, 8, 4], - "segmentConfiguration": "snake" + "segmentConfiguration": "snake", + "led_pin": 18, + "led_freq_hz": 800000, + "led_dma": 10, + "led_invert": false, + "led_channel": 0 }) } diff --git a/bin/install.sh b/bin/install.sh index c72949b..25c5dc8 100755 --- a/bin/install.sh +++ b/bin/install.sh @@ -98,69 +98,44 @@ tput sgr0 tput sc tput bel -piModel=0 -printf "\n\n\n" # So that the menu just erases things it has alredy written -while : -do - tput cuu 3 - tput ed - tput sc - tput setaf 8 - - if [[ piModel -eq 0 ]]; then - tput sgr0; fi - printf '%s\n' "- Raspberry Pi B" - tput setaf 8 - if [[ piModel -eq 1 ]]; then - tput sgr0; fi - printf '%s\n' "- Raspberry Pi B+" - tput setaf 8 - if [[ piModel -eq 2 ]]; then - tput sgr0; fi - printf '%s\n' "- Raspberry Pi Model 2" - tput setaf 8 - - read -sn1 key - if [ "$key" == "j" ]; then - piModel=$((piModel+1)) - if [[ piModel -gt 2 ]]; then - piModel=2 - fi - fi - if [ "$key" == "k" ]; then - piModel=$((piModel-1)) - if [[ piModel -lt 0 ]]; then - piModel=0 - fi - fi - if [ "$key" == "" ]; then - tput cuu 4 - tput ed - tput sgr0 - printf "%s\e[0;34m%s\e[0m\n" ". Which rPi is this? " "ListItem #$piModel" - break - fi - -done - - tput setaf 4 printf ". Installing the app itself...\n" tput sgr0 +# Create user 'luxcena-neo' +tput setaf 8 +printf '%s\n' " - Creating user 'lux-neo'..." +username="lux-neo" +egrep "^$username" /etc/passwd >/dev/null +if [ $? -eq 0 ]; then + echo "$username exists!" + exit 1 +else + #pass=$(perl -e 'print crypt($ARGV[0], "password")' $password) + useradd -m $username + [ $? -eq 0 ] && echo "User has been added to system!" || { printf "\n\nInstall failed.\n"; exit 1; } +fi +tput sgr0 + +# Change to the new user +tput setaf 8 +printf '%s\n' " - Changing to new user..." +sudo su lux-neo +tput sgr0 + # First we make our directories tput setaf 8 printf '%s\n' " - Making app-dir (/bin/luxcena-neo)..." tput sgr0 -mkdir ~/luxcena-neo-install || { printf "\n\nInstall failed.\n"; exit 1; } -mkdir ~/luxcena-neo-install/src || { printf "\n\nInstall failed.\n"; exit 1; } -mkdir ~/luxcena-neo-install/userdata || { printf "\n\nInstall failed.\n"; exit 1; } +mkdir ~/install || { printf "\n\nInstall failed.\n"; exit 1; } +mkdir ~/install/src || { printf "\n\nInstall failed.\n"; exit 1; } +mkdir ~/install/userdata || { printf "\n\nInstall failed.\n"; exit 1; } # Third we copy the source into the correct swap-folder tput setaf 8 printf '%s\n' " - Copying sourceCode to app-dir..." tput sgr0 -cp -r . ~/luxcena-neo-install/src || { printf "\n\nInstall failed.\n"; exit 1; } +cp -r . ~/install/src || { printf "\n\nInstall failed.\n"; exit 1; } # fourth we run npm i tput setaf 8 @@ -168,7 +143,7 @@ printf '%s\n' " - Running npm i..." tput sgr0 tput sc export NODE_ENV=production || { printf "\n\nInstall failed.\n"; exit 1; } -npm --prefix ~/luxcena-neo-install/src install ~/luxcena-neo-install/src --only=production || { printf "\n\nInstall failed.\n"; exit 1; } # This is probably a bit overkill to have --only=... but better safe than sorry? +npm --prefix ~/install/src install ~/install/src --only=production || { printf "\n\nInstall failed.\n"; exit 1; } # This is probably a bit overkill to have --only=... but better safe than sorry? tput rc; tput ed # Fifth we add the service files diff --git a/src/compileAndRun/pythonSupportFiles/LuxcenaNeo/Strip.py b/src/compileAndRun/pythonSupportFiles/LuxcenaNeo/Strip.py index c4ac8c9..f5beaa4 100644 --- a/src/compileAndRun/pythonSupportFiles/LuxcenaNeo/Strip.py +++ b/src/compileAndRun/pythonSupportFiles/LuxcenaNeo/Strip.py @@ -1,6 +1,161 @@ +#from neopixel import * +import atexit +import _rpi_ws281x as ws + class Strip: - def __init__(self, segments, segmentConfiguration): - self.segments = segments - self.segmentConfiguration = segmentConfiguration - return + def __init__(self, stripConf): + """Class to represent a NeoPixel/WS281x LED display. Num should be the + number of pixels in the display, and pin should be the GPIO pin connected + to the display signal line (must be a PWM pin like 18!). Optional + parameters are freq, the frequency of the display signal in hertz (default + 800khz), dma, the DMA channel to use (default 10), invert, a boolean + specifying if the signal line should be inverted (default False), and + channel, the PWM channel to use (defaults to 0). + """ + self.SEGMENTS = stripConf["segments"] + self.SEGMENT_CONFIG = stripConf["segment_config"] + + self.LED_FREQ_HZ = stripConf["led_freq_hz"] # LED signal frequency in hertz (usually 800khz) + self.LED_CHANNEL = stripConf["led_channel"] # Set to '1' for GPIOs 13, 19, 41, 45, 53 + self.LED_INVERT = stripConf["led_invert"] # True to invert the signal, (when using NPN transistor level shift) + self.LED_PIN = stripConf["led_pin"] # 18 uses PWM, 10 uses SPI /dev/spidev0.0 + self.LED_DMA = stripConf["led_dma"] # DMA channel for generating the signal, on the newer ones, try 10 + self.LED_COUNT = sum(self.SEGMENTS) # Number of LEDs in strip + + + self.LED_BRIGHTNESS = 255 + + # Create ws2811_t structure and fill in parameters. + self._leds = ws.new_ws2811_t() + + # Initialize the channels to zero + for channum in range(2): + chan = ws.ws2811_channel_get(self._leds, channum) + ws.ws2811_channel_t_count_set(chan, 0) + ws.ws2811_channel_t_gpionum_set(chan, 0) + ws.ws2811_channel_t_invert_set(chan, 0) + ws.ws2811_channel_t_brightness_set(chan, 0) + + # Initialize the channel in use + self._channel = ws.ws2811_channel_get(self._leds, channel) + ws.ws2811_channel_t_count_set(self._channel, num) + ws.ws2811_channel_t_gpionum_set(self._channel, pin) + ws.ws2811_channel_t_invert_set(self._channel, 0 if not invert else 1) + ws.ws2811_channel_t_brightness_set(self._channel, brightness) + ws.ws2811_channel_t_strip_type_set(self._channel, strip_type) + + # Initialize the controller + ws.ws2811_t_freq_set(self._leds, freq_hz) + ws.ws2811_t_dmanum_set(self._leds, dma) + + # Grab the led data array. + self._led_data = _LED_Data(self._channel, num) + + # Substitute for __del__, traps an exit condition and cleans up properly + atexit.register(self._cleanup) + + def _cleanup(self): + # Clean up memory used by the library when not needed anymore. + if self._leds is not None: + ws.delete_ws2811_t(self._leds) + self._leds = None + self._channel = None + + def begin(self): + """Initialize library, must be called once before other functions are + called. + """ + resp = ws.ws2811_init(self._leds) + if resp != ws.WS2811_SUCCESS: + message = ws.ws2811_get_return_t_str(resp) + raise RuntimeError('ws2811_init failed with code {0} ({1})'.format(resp, message)) + + def show(self): + """Update the display with the data from the LED buffer.""" + resp = ws.ws2811_render(self._leds) + if resp != ws.WS2811_SUCCESS: + message = ws.ws2811_get_return_t_str(resp) + raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, message)) + + def setPixelColor(self, n, color): + """Set LED at position n to the provided 24-bit color value (in RGB order). + """ + self._led_data[n] = color + + def setPixelColorRGB(self, n, red, green, blue, white = 0): + """Set LED at position n to the provided red, green, and blue color. + Each color component should be a value from 0 to 255 (where 0 is the + lowest intensity and 255 is the highest intensity). + """ + self.setPixelColor(n, Color(red, green, blue, white)) + + def setBrightness(self, brightness): + """Scale each LED in the buffer by the provided brightness. A brightness + of 0 is the darkest and 255 is the brightest. + """ + ws.ws2811_channel_t_brightness_set(self._channel, brightness) + + def getBrightness(self): + """Get the brightness value for each LED in the buffer. A brightness + of 0 is the darkest and 255 is the brightest. + """ + return ws.ws2811_channel_t_brightness_get(self._channel) + + def getPixels(self): + """Return an object which allows access to the LED display data as if + it were a sequence of 24-bit RGB values. + """ + return self._led_data + + def numPixels(self): + """Return the number of pixels in the display.""" + return ws.ws2811_channel_t_count_get(self._channel) + + def getPixelColor(self, n): + """Get the 24-bit RGB color value for the LED at position n.""" + return self._led_data[n] + + +def Color(red, green, blue, white = 0): + """Convert the provided red, green, blue color to a 24-bit color value. + Each color component should be a value 0-255 where 0 is the lowest intensity + and 255 is the highest intensity. + """ + return (white << 24) | (red << 16)| (green << 8) | blue + + +class _LED_Data(object): + """Wrapper class which makes a SWIG LED color data array look and feel like + a Python list of integers. + """ + def __init__(self, channel, size): + self.size = size + self.channel = channel + + def __getitem__(self, pos): + """Return the 24-bit RGB color value at the provided position or slice + of positions. + """ + # Handle if a slice of positions are passed in by grabbing all the values + # and returning them in a list. + if isinstance(pos, slice): + return [ws.ws2811_led_get(self.channel, n) for n in xrange(*pos.indices(self.size))] + # Else assume the passed in value is a number to the position. + else: + return ws.ws2811_led_get(self.channel, pos) + + def __setitem__(self, pos, value): + """Set the 24-bit RGB color value at the provided position or slice of + positions. + """ + # Handle if a slice of positions are passed in by setting the appropriate + # LED data values to the provided values. + if isinstance(pos, slice): + index = 0 + for n in xrange(*pos.indices(self.size)): + ws.ws2811_led_set(self.channel, n, value[index]) + index += 1 + # Else assume the passed in value is a number to the position. + else: + return ws.ws2811_led_set(self.channel, pos, value) diff --git a/src/compileAndRun/pythonSupportFiles/entry.py b/src/compileAndRun/pythonSupportFiles/entry.py index 4ba1031..3dab945 100644 --- a/src/compileAndRun/pythonSupportFiles/entry.py +++ b/src/compileAndRun/pythonSupportFiles/entry.py @@ -49,14 +49,12 @@ def main(): print ("> Loading pixel-configuration...") with open(config_dir + "strip.json", "r") as rawStripConf: stripConf = json.load(rawStripConf) - segments = stripConf["segments"] - segmentConfiguration = stripConf["segmentConfiguration"] print ("> Initializing script...") moduleSc = importlib.import_module("script") if ("LuxcenaNeo" in dir(moduleSc)): - moduleSc.LuxcenaNeo.strip = moduleSc.LuxcenaNeo.Strip(segments, segmentConfiguration) + moduleSc.LuxcenaNeo.strip = moduleSc.LuxcenaNeo.Strip(stripConf) elif ("neo" in dir(moduleSc)): moduleSc.neo.strip = moduleSc.neo.Strip(segments, segmentConfiguration) else: -- cgit v1.2.3