From 84bb18465a8efcaa3bddae6c0aa796f43be57284 Mon Sep 17 00:00:00 2001 From: Ravi Dudhagra Date: Fri, 24 Dec 2021 22:17:18 +0000 Subject: [PATCH] Improved led strip controller - Faster communication between server and controller - More robust protocol with start/end characters - Update rate from client to led strip ~10x faster - Ack sent from controller to server, server retries if nothing received - Server automatically flashes led strip controller on launch - New Christmas and Confetti light modes - Removed slow rainbow - Added slider to adjust speed (led refresh rate) - Minor code-style improvements - Read serial data using serialEvent(), store in buffer --- Light Strip Controller/main/christmas.h | 41 ++++ Light Strip Controller/main/colorpulse.h | 1 - Light Strip Controller/main/confetti.h | 28 +++ Light Strip Controller/main/constants.h | 28 ++- Light Strip Controller/main/main.ino | 238 +++++++++++++-------- Light Strip Controller/main/mode.h | 17 +- Light Strip Controller/main/slowrainbow.h | 28 --- Light Strip Controller/util/serial_send.py | 4 +- Website/flash-light-strip-controller.sh | 32 +++ Website/package-lock.json | 5 + Website/package.json | 1 + Website/server/routes/led_controller.js | 53 ++++- Website/src/app/components/Led.jsx | 61 ++++-- 13 files changed, 374 insertions(+), 163 deletions(-) create mode 100644 Light Strip Controller/main/christmas.h create mode 100644 Light Strip Controller/main/confetti.h delete mode 100644 Light Strip Controller/main/slowrainbow.h create mode 100755 Website/flash-light-strip-controller.sh diff --git a/Light Strip Controller/main/christmas.h b/Light Strip Controller/main/christmas.h new file mode 100644 index 0000000..782d919 --- /dev/null +++ b/Light Strip Controller/main/christmas.h @@ -0,0 +1,41 @@ +#ifndef LIGHT_STRIP_CONTROLLER_CHRISTMAS_H + +#define LIGHT_STRIP_CONTROLLER_CHRISTMAS_H + +#include "constants.h" +#include + +void christmas(CRGB *leds, uint8_t *dat) +{ + if (*dat == 0) + { + // White, Green, White, Red + fill_gradient_RGB(leds, 0, CRGB::CadetBlue, NUM_LEDS / 4 - 1, CRGB::Green); + fill_gradient_RGB(leds, NUM_LEDS / 4, CRGB::Green, NUM_LEDS / 2 - 1, CRGB::CadetBlue); + fill_gradient_RGB(leds, NUM_LEDS / 2, CRGB::CadetBlue, NUM_LEDS / 4 * 3 - 1, CRGB::Red); + fill_gradient_RGB(leds, NUM_LEDS / 4 * 3, CRGB::Red, NUM_LEDS - 1, CRGB::CadetBlue); + *dat = 1; + } + else + { + // save the first element + CRGB first = leds[0]; + // shift every element down one + for (int i = 1; i < NUM_LEDS; i++) + { + leds[i - 1] = leds[i]; + } + // put the first element in the last slot + leds[NUM_LEDS - 1] = first; + } +} + +uint8_t *init_christmas_dat() +{ + uint8_t *dat = (uint8_t *)malloc(sizeof(uint8_t)); + *dat = 0; + + return dat; +} + +#endif \ No newline at end of file diff --git a/Light Strip Controller/main/colorpulse.h b/Light Strip Controller/main/colorpulse.h index 306ae8f..14ec2f3 100644 --- a/Light Strip Controller/main/colorpulse.h +++ b/Light Strip Controller/main/colorpulse.h @@ -8,7 +8,6 @@ #define PI 128 // This is with relation to 2pi=256, used by 8-bit FastLED trig funcs const uint8_t N_OVER_2 = NUM_LEDS / 2; -const uint16_t PULSE_MAX_RNG_VAL = (uint16_t)(16384.0 * PULSE_FREQUENCY / FRAMES_PER_SECOND); const uint8_t A = 255 / NUM_LEDS; const CRGB BLACK = CRGB(0, 0, 0); diff --git a/Light Strip Controller/main/confetti.h b/Light Strip Controller/main/confetti.h new file mode 100644 index 0000000..4e1c273 --- /dev/null +++ b/Light Strip Controller/main/confetti.h @@ -0,0 +1,28 @@ +#ifndef LIGHT_STRIP_CONTROLLER_CONFETTI_H + +#define LIGHT_STRIP_CONTROLLER_CONFETTI_H + +#include "constants.h" +#include + +// Adapted from https://github.com/atuline/FastLED-Demos/blob/master/confetti/confetti.ino + +void confetti(CRGB *leds, uint8_t *dat) +{ + (void)dat; + + fadeToBlackBy(leds, NUM_LEDS, CONFETTI_DECAY_RATE); + int pos = random16(NUM_LEDS); + leds[pos] += CHSV((*dat + random16(256))/4 , CONFETTI_SATURATION, 255); // 12 bits for hue so that the hue increment isn't too quick. + *dat++; +} + +uint8_t *init_confetti_dat() +{ + uint8_t *dat = (uint8_t *)malloc(sizeof(uint8_t)); + *dat = 0; + + return dat; +} + +#endif \ No newline at end of file diff --git a/Light Strip Controller/main/constants.h b/Light Strip Controller/main/constants.h index 106ad67..d127357 100644 --- a/Light Strip Controller/main/constants.h +++ b/Light Strip Controller/main/constants.h @@ -3,8 +3,16 @@ #define LIGHT_STRIP_CONTROLLER_CONSTANTS_H // General Constants -#define DEBUG true -#define SERIAL_BAUD_RATE 2400 +#define DEBUG false +#define SERIAL_BAUD_RATE 115200 +#define BUF_SIZE 32 + +// Communication Protocol Constants +#define START_CHAR '[' +#define END_CHAR ']' +#define BRIGHTNESS_CMD '!' +#define FPS_CMD '@' +#define RGB_CMD '#' // LED Strip Constants #define DATA_PIN 3 @@ -12,33 +20,33 @@ #define NUM_LEDS 240 #define BRIGHTNESS 255 #define MAX_MILLIAMPS 12000 -#define FRAMES_PER_SECOND 25 // Color Modes #define OFF 0 #define RAINBOW 1 -#define SLOW_RAINBOW 2 +#define CHRISTMAS 2 #define COLOR_PULSE 3 #define AMBIANCE 4 +#define CONFETTI 5 #define SOLID_COLOR 255 // Not to be used by client...only internally -// Slow Rainbow Mode Constants -#define SLOW_RAINBOW_MULTIPLIER 10 // This number is how many times slower \ - // the slow rainbow effect is compared \ - // to the normal rainbow effect - // Color Pulse Mode Constants #define PULSE_FREQUENCY 3 // Frequency for a new pulse in Hz \ // Will be on average this value... \ // actual pulses will be created using rng #define PULSE_MIN_SATURATION 225 // Out of 255 #define PULSE_INTENSITY 50 // bigger the number, longer the leds stay bright, 0 is no change -#define PULSE_BACKGROUND_BRIGHTNESS 128 // 0..255 +#define PULSE_BACKGROUND_BRIGHTNESS 80 // 0..255 // Ambiance Mode Constants #define AMBIANCE_SATURATION 100 #define AMBIANCE_CHANGE_RATE 0.03 // Defines the bounds for the random walk #define AMBIANCE_MAX_CHANGE_RATE 0.3 +// Confetti Mode Constants +#define CONFETTI_DECAY_RATE 2 // Low values = slower fade +#define CONFETTI_SATURATION 150 + + #endif diff --git a/Light Strip Controller/main/main.ino b/Light Strip Controller/main/main.ino index d8203e7..265730d 100644 --- a/Light Strip Controller/main/main.ino +++ b/Light Strip Controller/main/main.ino @@ -9,6 +9,8 @@ CRGB leds[NUM_LEDS]; uint8_t mode = OFF; // Start with leds off uint8_t *dat; +uint16_t millis_per_frame = 1e3 / 25; + void setup() { delay(1000); // 1 second delay for recovery @@ -27,123 +29,175 @@ void setup() dat = init_dat(mode); } +char inputBuf[BUF_SIZE]; // a String to hold incoming data +char cmd[BUF_SIZE]; // a String to hold the finished command +uint8_t buf_pos = 0; // Current position in the buffer (and length of stored string) +bool newCommandReady = false; // whether the string is complete +bool processingCommand = false; // a bool to prevent modifying cmd while reading it + void loop() +{ + // Compute next frame + EVERY_N_MILLIS_I(thisTimer, millis_per_frame) + { + handle_serial_data(); + process_cmd(); + thisTimer.setPeriod(millis_per_frame); + next_frame(mode, leds, dat); + FastLED.show(); + // Serial.println(*dat); + } +} + +void process_cmd() { // Check for new mode - if (Serial.available()) + if (newCommandReady) { - // Set new mode - uint8_t newMode = Serial.read(); - if (newMode != '\r' && newMode != '\n') - { - if (DEBUG) - { - Serial.print("Setting new mode: "); - Serial.println(newMode); - } + newCommandReady = false; + processingCommand = true; - if (newMode == '!') + // Verify start character + if (cmd[0] == START_CHAR) + { + // Set new mode + uint8_t newMode = (uint8_t)cmd[1]; + if (newMode != '\r' && newMode != '\n') { - // Set new brightness - uint8_t t = 1; - while (t && Serial.available() < 1) + if (DEBUG) { - // Wait a bit to get all bytes from serial (b) - // Limited to 255ms (by size of uint8_t) - FastLED.delay(1); - if (DEBUG) - Serial.print("."); - t++; + Serial.print("Setting new mode: "); + Serial.println(newMode); } - if (Serial.available() < 1) + if (newMode == BRIGHTNESS_CMD) { - while (Serial.available()) - Serial.read(); // flush serial buffer - if (DEBUG) - Serial.println(); - Serial.println("Invalid brightness input..."); - return; + // Check that the command is valid + if (cmd[3] == END_CHAR) + { + // Set new brightness + uint8_t b = cmd[2]; + + if (DEBUG) + { + Serial.print("Setting brightness: "); + Serial.println(b); + } + + FastLED.setBrightness(b); + + send_ack(); + } } - - uint8_t b = Serial.read(); - - if (DEBUG) + else if (newMode == FPS_CMD) { - Serial.print("Setting brightness: "); - Serial.println(b); + // Check that the command is valid + if (cmd[3] == END_CHAR) + { + // Set new fps + uint16_t fps = cmd[2]; + millis_per_frame = 1e3 / fps; + + if (DEBUG) + { + Serial.print("Setting FPS: "); + Serial.println(fps); + } + + send_ack(); + } } - - FastLED.setBrightness(b); - } - else if (newMode == '#') - { - // We are sending a solid color, not a predefined mode - // act accordingly... - - uint8_t t = 1; - while (t && Serial.available() < 3) + else if (newMode == RGB_CMD) { - // Wait a bit to get all three bytes from serial (r,g,b) - // Limited to 255ms (by size of uint8_t) - FastLED.delay(1); - if (DEBUG) - Serial.print("."); - t++; + // Check that the command is valid + if (cmd[5] == END_CHAR) + { + // We are sending a solid color, not a predefined mode + // act accordingly... + uint8_t r = cmd[2]; + uint8_t g = cmd[3]; + uint8_t b = cmd[4]; + + if (DEBUG) + { + Serial.print("Setting solid color: ("); + Serial.print(r); + Serial.print(", "); + Serial.print(g); + Serial.print(", "); + Serial.print(b); + Serial.println(")"); + } + + // Free old dat + free(dat); + + // Init dat to solid color type + dat = init_solid_color_dat(r, g, b); // Assume rgb format + + mode = SOLID_COLOR; + + send_ack(); + } } - - if (Serial.available() < 3) + else { - while (Serial.available()) - Serial.read(); // flush serial buffer - if (DEBUG) - Serial.println(); - Serial.println("Invalid solid color input..."); - return; - } + // Check that the command is valid + if (cmd[2] == END_CHAR) + { + mode = newMode; - uint8_t r = Serial.read(); - uint8_t g = Serial.read(); - uint8_t b = Serial.read(); + // Free old dat + free(dat); - if (DEBUG) - { - Serial.print("Setting solid color: ("); - Serial.print(r); - Serial.print(", "); - Serial.print(g); - Serial.print(", "); - Serial.print(b); - Serial.println(")"); + // Init dat to correct type + dat = init_dat(mode); + + send_ack(); + } } + } + } - // Free old dat - free(dat); + processingCommand = false; + } +} - // Init dat to solid color type - dat = init_solid_color_dat(r, g, b); // Assume rgb format +void send_ack() +{ + Serial.println("ack"); +} - mode = SOLID_COLOR; - } - else - { - mode = newMode; +void handle_serial_data() +{ + while (Serial.available()) + { + // get the new byte: + char inChar = (char)Serial.read(); + // if the incoming character is the start character, we are receiving the + // beginning of a new command. Reset the buffer + // Or, reset the buffer if we've filled it up. + if (inChar == START_CHAR || buf_pos >= BUF_SIZE) + { + memset(inputBuf, 0, BUF_SIZE); + buf_pos = 0; + } - // Free old dat - free(dat); + inputBuf[buf_pos] = inChar; + buf_pos++; - // Init dat to correct type - dat = init_dat(mode); + // if the incoming character is the end character, set a flag so the + // main loop can do something about it: + if (inChar == END_CHAR) + { + // If we're processing a command already, just throw this new one away + if (!processingCommand) + { + memcpy(cmd, inputBuf, BUF_SIZE); + newCommandReady = true; } + memset(inputBuf, 0, BUF_SIZE); + buf_pos = 0; } } - - // Compute next frame - next_frame(mode, leds, dat); - FastLED.show(); - - // Serial.println(*dat); - - // Wait until next frame - FastLED.delay(1e3 / FRAMES_PER_SECOND); } diff --git a/Light Strip Controller/main/mode.h b/Light Strip Controller/main/mode.h index 119db85..f7c0bb4 100644 --- a/Light Strip Controller/main/mode.h +++ b/Light Strip Controller/main/mode.h @@ -5,10 +5,11 @@ #include "constants.h" #include "off.h" #include "rainbow.h" -#include "slowrainbow.h" +#include "christmas.h" #include "solidcolor.h" #include "colorpulse.h" #include "ambiance.h" +#include "confetti.h" void next_frame(uint8_t mode, CRGB *leds, uint8_t *dat) { @@ -23,8 +24,8 @@ void next_frame(uint8_t mode, CRGB *leds, uint8_t *dat) case RAINBOW: updateFn = &rainbow; break; - case SLOW_RAINBOW: - updateFn = &slow_rainbow; + case CHRISTMAS: + updateFn = &christmas; break; case SOLID_COLOR: updateFn = &solid_color; @@ -35,6 +36,9 @@ void next_frame(uint8_t mode, CRGB *leds, uint8_t *dat) case AMBIANCE: updateFn = &ambiance; break; + case CONFETTI: + updateFn = &confetti; + break; default: updateFn = &off; // Turn off by default break; @@ -56,8 +60,8 @@ uint8_t *init_dat(uint8_t mode) case RAINBOW: initFn = *init_rainbow_dat; break; - case SLOW_RAINBOW: - initFn = *init_slow_rainbow_dat; + case CHRISTMAS: + initFn = *init_christmas_dat; break; case COLOR_PULSE: initFn = &init_color_pulse_dat; @@ -65,6 +69,9 @@ uint8_t *init_dat(uint8_t mode) case AMBIANCE: initFn = &init_ambiance_dat; break; + case CONFETTI: + initFn = &init_confetti_dat; + break; default: initFn = *init_off_dat; // Turn off by default break; diff --git a/Light Strip Controller/main/slowrainbow.h b/Light Strip Controller/main/slowrainbow.h deleted file mode 100644 index 9ee7d65..0000000 --- a/Light Strip Controller/main/slowrainbow.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef LIGHT_STRIP_CONTROLLER_SLOW_RAINBOW_H - -#define LIGHT_STRIP_CONTROLLER_SLOW_RAINBOW_H - -#include "constants.h" -#include - - -void slow_rainbow(CRGB *leds, uint8_t *dat) -{ - fill_rainbow(leds, NUM_LEDS, dat[1], 1); - dat[0]++; - if (dat[0] >= 5) - { - dat[1]++; - dat[0] = 0; - } -} - -uint8_t *init_slow_rainbow_dat() -{ - uint8_t *dat = (uint8_t*) calloc(2, sizeof(uint8_t)); - dat[0] = 0; // Local counter to slow down rainbow size - dat[1] = 0; // Counter for hue offest, same as rainbow - return dat; -} - -#endif \ No newline at end of file diff --git a/Light Strip Controller/util/serial_send.py b/Light Strip Controller/util/serial_send.py index 6c645bc..2b88d3b 100644 --- a/Light Strip Controller/util/serial_send.py +++ b/Light Strip Controller/util/serial_send.py @@ -1,10 +1,10 @@ import serial, time -ser = serial.Serial('/dev/tty.usbmodem142201', 2400, timeout=1) # open serial port +ser = serial.Serial('/dev/tty.usbmodem142201', 115200, timeout=1) # open serial port time.sleep(4) print("Writing command...") -ser.write(b'#\xff\xcc\x33') +ser.write(b'[#\xff\xcc\x33]\n') print(ser.readline()) print(ser.readline()) diff --git a/Website/flash-light-strip-controller.sh b/Website/flash-light-strip-controller.sh new file mode 100755 index 0000000..83f3fa2 --- /dev/null +++ b/Website/flash-light-strip-controller.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +############# Install Arduino ############### + +# Install Arduino CLI +if [ ! -f /home/pi/arduino-cli ] +then + echo "arduino-cli not found! Installing..." + curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/home/pi/ sh + chmod +x /home/pi/arduino-cli +fi + +# Install AVR Boards +/home/pi/arduino-cli core install arduino:avr + +# Install FastLED +/home/pi/arduino-cli lib install FastLED + +############## Flash sketch ############### + +# cd to the script's directory +cd "${0%/*}" + +# Compile +/home/pi/arduino-cli compile -b arduino:avr:uno "../Light Strip Controller/main" + +# Upload +source .env +/home/pi/arduino-cli upload -p $LED_STRIP_ARDUINO_SERIAL_PORT -b arduino:avr:uno "../Light Strip Controller/main" -t -v + + +echo "Done!" diff --git a/Website/package-lock.json b/Website/package-lock.json index d3f50bc..0a171ee 100644 --- a/Website/package-lock.json +++ b/Website/package-lock.json @@ -7859,6 +7859,11 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz", "integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==" }, + "node-cmd": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-cmd/-/node-cmd-5.0.0.tgz", + "integrity": "sha512-4sQTJmsS5uZKAPz/Df9fnIbmvOySfGdW+UreH4X5NcAOOpKjaE+K5wf4ehNBbZVPo0vQ36RkRnhhsXXJAT+Syw==" + }, "node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", diff --git a/Website/package.json b/Website/package.json index f46e704..07ad92f 100644 --- a/Website/package.json +++ b/Website/package.json @@ -25,6 +25,7 @@ "express-fileupload": "^1.1.9", "gcodetogeometry": "^1.0.0", "jquery": "^3.5.1", + "node-cmd": "^5.0.0", "node-sass": "^4.5.3", "node-sass-middleware": "^0.11.0", "react": "^16.6.3", diff --git a/Website/server/routes/led_controller.js b/Website/server/routes/led_controller.js index afe1a69..33e3c87 100644 --- a/Website/server/routes/led_controller.js +++ b/Website/server/routes/led_controller.js @@ -1,6 +1,10 @@ require("dotenv").config(); import express from 'express'; +import path from 'path'; + +var cmd = require('node-cmd'); +cmd.runSync(path.resolve(path.join(__dirname, '../../flash-light-strip-controller.sh'))); const SerialPort = require('serialport'); const router = express.Router(); @@ -10,8 +14,22 @@ const PORT = process.env.LED_STRIP_ARDUINO_SERIAL_PORT; var mode = "0"; const port = new SerialPort(PORT, { - baudRate: 2400, -}).on("error", (e) => console.log(e)); + baudRate: 115200, +}); +port.on("error", (e) => console.log(e)); + +var cmd_interval = null; +var cmd_res = null; +port.on('data', function (data) { + data = data.toString(); + console.log(`Received data from led strip controller: ${data}`); + if (cmd_interval != null && cmd_res != null && data.includes("ack")) { + clearInterval(cmd_interval); + cmd_interval = null; + cmd_res.sendStatus(200); + cmd_res = null; + } +}) router.post("/set", function (req, res) { var cmd = Buffer.from(decodeURIComponent(req.body.cmd)); @@ -33,15 +51,40 @@ router.post("/set", function (req, res) { parseInt(cmd.slice(1, 3).toString(), 16), ]); break; + case '@'.charCodeAt(0): + // Setting new speed, no need to change mode + cmd = Buffer.from([ + '@'.charCodeAt(0), + parseInt(cmd.slice(1, 3).toString(), 16), + ]); + break; default: // Setting mode to a predefined pattern mode = "" + cmd[0]; cmd = cmd.slice(0, 1); break; } - port.write(cmd); - console.log("Sent cmd to led strip: [" + Array.from(cmd.values()) + "]"); - res.sendStatus(200); + + // Add start and end characters + cmd = Buffer.concat([Buffer.from("["), cmd, Buffer.from("]\n")]) + port.flush(() => { + // Send same command several times because FastLED messes with Arduino Serial (so some packets are lost) + cmd_res = res; + var send_cnt = 0; + cmd_interval = setInterval(() => { + port.write(cmd); + port.drain(() => { + console.log("Sent cmd to led strip: [" + Array.from(cmd.values()) + "]"); + }); + + if (++send_cnt === 50) { + clearInterval(cmd_interval); + cmd_interval = null; + cmd_res.sendStatus(200); + cmd_res = null; + } + }, 5); + }); }); router.get("/get", function (req, res) { diff --git a/Website/src/app/components/Led.jsx b/Website/src/app/components/Led.jsx index 6a2c652..84c5859 100644 --- a/Website/src/app/components/Led.jsx +++ b/Website/src/app/components/Led.jsx @@ -1,6 +1,7 @@ import React from "react"; import iro from "@jaames/iro"; import { Col, Card } from "react-bootstrap"; +import RangeSlider from "react-bootstrap-range-slider"; import Axios from "axios"; class Led extends React.Component { @@ -12,17 +13,17 @@ class Led extends React.Component { this.onColorChange; this.sendCmd = this.sendCmd.bind(this); - this.modes = ["Off", "Rainbow", "Slow Rainbow", "Color Pulse", "Ambiance"]; + this.modes = ["Off", "Rainbow", "Christmas", "Color Pulse", "Ambiance", "Confetti"]; this.colorChanging = false; this.brightnessChanging = false; - this.state = { mode: "" }; + this.state = { mode: "", speed: 25 }; } - sendCmd(modeString) { + async sendCmd(modeString) { console.log("Sent cmd: " + modeString); - Axios.post("/led/set", { cmd: encodeURIComponent(modeString) }); + await Axios.post("/led/set", { cmd: encodeURIComponent(modeString) }); } componentDidMount() { @@ -51,31 +52,27 @@ class Led extends React.Component { ], }); - var onColorChange = (color) => { - if(this.colorChanging) return; + var onColorChange = async (color) => { + if (this.colorChanging) return; this.colorChanging = true; - this.sendCmd(color.hexString); - this.setState({ mode: color.hexString }); colorPicker.off("color:change", onColorChange); - setTimeout(() => { - colorPicker.on("color:change", onColorChange); - this.colorChanging = false; - }, 250); + this.setState({ mode: color.hexString }); + await this.sendCmd(color.hexString); + colorPicker.on("color:change", onColorChange); + this.colorChanging = false; }; colorPicker.on("color:change", onColorChange); this.onColorChange = onColorChange; - var onBrightnessChange = (color) => { - if(this.brightnessChanging) return; + var onBrightnessChange = async (color) => { + if (this.brightnessChanging) return; this.brightnessChanging = true; - this.sendCmd("!" + Math.round(color.value * 2.55).toString(16)); brightnessSlider.off("color:change", onBrightnessChange); - setTimeout(() => { - brightnessSlider.on("color:change", onBrightnessChange); - this.brightnessChanging = false; - }, 250); + await this.sendCmd("!" + Math.round(color.value * 2.55).toString(16)); + brightnessSlider.on("color:change", onBrightnessChange); + this.brightnessChanging = false; }; brightnessSlider.on("color:change", onBrightnessChange); @@ -99,7 +96,31 @@ class Led extends React.Component { className="mt-3 text-center" ref={(ref) => (this.brightnessSliderRef = ref)} /> - + +
Speed:
+ + this.setState({ speed: e.target.value })} + variant="light" + min={1} + max={100} + tooltip="auto" + tooltipLabel={(currentValue) => `${currentValue}`} + inputProps={{ + onMouseUp: () => { + console.log("Set led speed to " + this.state.speed); + this.sendCmd("@" + Math.round(this.state.speed).toString(16)); + }, + onTouchEnd: () => { + console.log("Set led speed to " + this.state.speed); + this.sendCmd("@" + Math.round(this.state.speed).toString(16)); + }, + }} + /> + + + {this.modes.map((name, index) => { return (