diff --git a/assets/firmware/esp8266/AtmoOrb/AtmoOrb.ino b/assets/firmware/esp8266/AtmoOrb/AtmoOrb.ino index 8a19fd72..dcfc64e8 100644 --- a/assets/firmware/esp8266/AtmoOrb/AtmoOrb.ino +++ b/assets/firmware/esp8266/AtmoOrb/AtmoOrb.ino @@ -15,7 +15,7 @@ #include #define NUM_LEDS 24 // Number of leds -#define DATA_PIN 7 // Data pin for leds (the default pin 7 might correspond to pin 13 on some boards) +#define DATA_PIN D7 // Data pin for leds (the default pin 7 might correspond to pin 13 on some boards) #define SERIAL_DEBUG 0 // Serial debugging (0=Off, 1=On) #define ID 1 // Id of this lamp @@ -348,7 +348,7 @@ void identify() { FastLED.showColor(CRGB::LemonChiffon); delay(500); - FastLED.showColor(CRGB::Black); + FastLED.showColor(CRGB::Black); delay(500); } } diff --git a/assets/firmware/particle/photon/AtmoOrb_UDP.ino b/assets/firmware/particle/photon/AtmoOrb_UDP.ino new file mode 100644 index 00000000..415cec1c --- /dev/null +++ b/assets/firmware/particle/photon/AtmoOrb_UDP.ino @@ -0,0 +1,313 @@ +#include +FASTLED_USING_NAMESPACE; + +SYSTEM_THREAD(ENABLED); + +#if FASTLED_VERSION < 3001000 +#error "Requires FastLED 3.1 or later; check github for latest code." +#endif + +// WiFi +#define timeout 30000 +#define reconnect_delay 5000 + +// UDP +#define SERVER_PORT 49692 +#define DISCOVERY_PORT 49692 +UDP client; +IPAddress multicastIP(239, 15, 18, 2); + +// ORB +unsigned int orbID = 1; + +#define SERIAL_DEBUG 0 // Serial debugging (0=Off, 1=On) + +// LED +#define DATA_PIN 6 +#define NUM_LEDS 24 +CRGB leds[NUM_LEDS]; + +// UDP +#define BUFFER_SIZE 8 // 5 + 3 channels for 1 LED +#define BUFFER_SIZE_DISCOVERY 5 +#define TIMEOUT_MS 500 +uint8_t buffer[BUFFER_SIZE]; +uint8_t bufferDiscovery[BUFFER_SIZE_DISCOVERY]; +unsigned long lastWiFiCheck = 0; + +// SMOOTHING +#define SMOOTH_STEPS 50 // Steps to take for smoothing colors +#define SMOOTH_DELAY 4 // Delay between smoothing steps +#define SMOOTH_BLOCK 0 // Block incoming colors while smoothing + +byte nextColor[3]; +byte prevColor[3]; +byte currentColor[3]; +byte smoothStep = SMOOTH_STEPS; +unsigned long smoothMillis; + +// CUSTOM COLOR CORRECTIONS +#define RED_CORRECTION 255 +#define GREEN_CORRECTION 255 +#define BLUE_CORRECTION 255 +#include "Particle.h" + +void setup() +{ + // Leds - choose one correction method + // 1 - Custom color correction + FastLED.addLeds(leds, NUM_LEDS).setCorrection(CRGB(RED_CORRECTION, GREEN_CORRECTION, BLUE_CORRECTION)); + + // Set color + //setColor(40, 21, 0); + + // Uncomment the below lines to dim the single built-in led to 2% + ::RGB.control(true); + ::RGB.brightness(2); + ::RGB.control(false); + + // WiFi + lastWiFiCheck = millis(); + initWiFi(); + + // 2 - FastLED predefined color correction + //FastLED.addLeds(leds, NUM_LEDS).setCorrection(TypicalSMD5050); +} + +void initWiFi() +{ + // Delays added UDP client creation, required for WiFi reconnects as takes a bit for resources to be full available + + // Wait for WiFi connection + delay(500); + waitFor(WiFi.ready, timeout); + delay(reconnect_delay); + + // Multicast UDP + if(WiFi.ready()) + { + #if SERIAL_DEBUG == 1 + Serial.println(""); + Serial.print(F("Connected to ")); + Serial.println(WiFi.SSID()); + Serial.print(F("IP address: ")); + Serial.println(WiFi.localIP()); + #endif + + client.begin(SERVER_PORT); + delay(reconnect_delay); + client.joinMulticast(multicastIP); + + #if SERIAL_DEBUG == 1 + Serial.print(F("Listening to Multicast at ")); + Serial.print(multicastIP); + Serial.print(F(":")); + Serial.println(SERVER_PORT); + #endif + } +} + +void loop(){ + if (Network.listening()) + { + // If we are in listening mode (blinking dark blue), don't + // output by USB serial, because it can conflict with + // serial commands. + return; + } + + if(WiFi.ready() == false) { + #if SERIAL_DEBUG == 1 + Serial.print(F("Lost connection to ")); + Serial.print(WiFi.SSID()); + Serial.println(F(".")); + Serial.println(F("Trying to reconnect.")); + #endif + + initWiFi(); + } + + int packetSize = client.parsePacket(); + + if(packetSize == BUFFER_SIZE){ + + #if SERIAL_DEBUG == 1 + Serial.print(F("Packet size: ")); + Serial.println(packetSize); + #endif + client.read(buffer, BUFFER_SIZE); + //client.flush(); + + #if SERIAL_DEBUG == 1 + Serial.print(F("UDP Packet from ")); + Serial.println(client.remoteIP()); + for (int i = 0; i < BUFFER_SIZE; i++) + { + Serial.print(buffer[i]); + Serial.print(F(" ")); + } + Serial.println(""); + #endif + unsigned int i = 0; + + // Look for 0xC0FFEE + if(buffer[i++] == 0xC0 && buffer[i++] == 0xFF && buffer[i++] == 0xEE) + { + byte commandOptions = buffer[i++]; + byte rcvOrbID = buffer[i++]; + + byte red = buffer[i++]; + byte green = buffer[i++]; + byte blue = buffer[i++]; + + // Command options + // 1 = force off + // 2 = use lamp smoothing and validate by Orb ID + // 4 = validate by Orb ID + // 8 = discovery + // 9 = light-up Orb to identify by Orb ID + if(commandOptions == 1) + { + // Orb ID 0 = turn off all lights + // Otherwise turn off selectively + if(rcvOrbID == 0 || rcvOrbID == orbID) + { + smoothStep = SMOOTH_STEPS; + forceLedsOFF(); + } + + return; + } + else if(commandOptions == 2) + { + if(rcvOrbID != orbID) + { + return; + } + + setSmoothColor(red, green, blue); + } + else if(commandOptions == 4) + { + if(rcvOrbID != orbID) + { + return; + } + + smoothStep = SMOOTH_STEPS; + setColor(red, green, blue); + setSmoothColor(red, green, blue); + + return; + } + else if(commandOptions == 8) + { + #if SERIAL_DEBUG == 1 + Serial.print(F("Announce myself. OrbID: ")); + Serial.println(orbID); + #endif + // Respond to remote IP address with Orb ID + IPAddress remoteIP = client.remoteIP(); + bufferDiscovery[0] = orbID; + + client.sendPacket(bufferDiscovery, BUFFER_SIZE_DISCOVERY, remoteIP, DISCOVERY_PORT); + + // Clear buffer + memset(bufferDiscovery, 0, sizeof(bufferDiscovery)); + return; + } + else if(commandOptions == 9) + { + if(rcvOrbID == 0 || rcvOrbID == orbID) + { + #if SERIAL_DEBUG == 1 + Serial.print(F("Identify myself. OrbID: ")); + Serial.println(orbID); + #endif + identify(); + } + return; + } + } + + }else if(packetSize > 0){ + // Got malformed packet + } + + if (smoothStep < SMOOTH_STEPS && millis() >= (smoothMillis + (SMOOTH_DELAY * (smoothStep + 1)))) + { + smoothColor(); + } +} + +// Set color +void setColor(byte red, byte green, byte blue) +{ + for (byte i = 0; i < NUM_LEDS; i++) + { + leds[i] = CRGB(red, green, blue); + } + + FastLED.show(); +} + + +// Set a new color to smooth to +void setSmoothColor(byte red, byte green, byte blue) +{ + if (smoothStep == SMOOTH_STEPS || SMOOTH_BLOCK == 0) + { + if (nextColor[0] == red && nextColor[1] == green && nextColor[2] == blue) + { + return; + } + + prevColor[0] = currentColor[0]; + prevColor[1] = currentColor[1]; + prevColor[2] = currentColor[2]; + + nextColor[0] = red; + nextColor[1] = green; + nextColor[2] = blue; + + smoothMillis = millis(); + smoothStep = 0; + } +} + +// Display one step to the next color +void smoothColor() +{ + smoothStep++; + currentColor[0] = prevColor[0] + (((nextColor[0] - prevColor[0]) * smoothStep) / SMOOTH_STEPS); + currentColor[1] = prevColor[1] + (((nextColor[1] - prevColor[1]) * smoothStep) / SMOOTH_STEPS); + currentColor[2] = prevColor[2] + (((nextColor[2] - prevColor[2]) * smoothStep) / SMOOTH_STEPS); + + setColor(currentColor[0], currentColor[1], currentColor[2]); +} + +// Force all leds OFF +void forceLedsOFF() +{ + setColor(0,0,0); + clearSmoothColors(); +} + +// Clear smooth color byte arrays +void clearSmoothColors() +{ + memset(prevColor, 0, sizeof(prevColor)); + memset(currentColor, 0, sizeof(nextColor)); + memset(nextColor, 0, sizeof(nextColor)); +} + +void identify() +{ + for (byte i = 0; i < 3; i++) + { + FastLED.showColor(CRGB::LemonChiffon); + delay(500); + FastLED.showColor(CRGB::Black); + delay(500); + } +} diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index 8994c4b5..eec08e8a 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -546,6 +546,8 @@ "edt_dev_spec_baudrate_title": "Baudrate", "edt_dev_spec_blackLightsTimeout_title": "Signal detection timeout on black", "edt_dev_spec_brightnessFactor_title": "Brightness factor", + "edt_dev_spec_brightnessMax_title": "Brightness maximum", + "edt_dev_spec_brightnessMin_title": "Brightness minimum", "edt_dev_spec_brightnessOverwrite_title": "Overwrite brightness", "edt_dev_spec_brightnessThreshold_title": "Signal detection brightness minimum", "edt_dev_spec_brightness_title": "Brightness", diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js index aaca22fa..8fc3359d 100755 --- a/assets/webconfig/js/content_leds.js +++ b/assets/webconfig/js/content_leds.js @@ -1631,7 +1631,10 @@ function saveLedConfig(genDefLayout = false) { case "cololight": var host = conf_editor.getEditor("root.specificOptions.host").getValue(); - result.smoothing = { enable: false }; + if (window.serverConfig.device.type !== ledType) { + //smoothing off, if new device + result.smoothing = { enable: false }; + } if (genDefLayout === true) { @@ -1667,7 +1670,11 @@ function saveLedConfig(genDefLayout = false) { case "nanoleaf": case "wled": - result.smoothing = { enable: false }; + case "yeelight": + if (window.serverConfig.device.type !== ledType) { + //smoothing off, if new device + result.smoothing = { enable: false }; + } case "adalight": case "atmo": diff --git a/assets/webconfig/js/ui_utils.js b/assets/webconfig/js/ui_utils.js index be6741b7..36df6eff 100644 --- a/assets/webconfig/js/ui_utils.js +++ b/assets/webconfig/js/ui_utils.js @@ -171,7 +171,7 @@ function initLanguageSelection() { } function updateUiOnInstance(inst) { - $("#active_instance_friendly_name").text(window.serverInfo.instance[inst].friendly_name); + $("#active_instance_friendly_name").text(getInstanceNameByIndex(inst)); if (window.serverInfo.instance.filter(entry => entry.running).length > 1) { $('#btn_hypinstanceswitch').toggle(true); $('#active_instance_dropdown').prop('disabled', false); diff --git a/assets/webconfig/js/wizard.js b/assets/webconfig/js/wizard.js index a2a028d8..12b966b6 100755 --- a/assets/webconfig/js/wizard.js +++ b/assets/webconfig/js/wizard.js @@ -1126,15 +1126,19 @@ function beginWizardHue() { d.useEntertainmentAPI = false; d.hardwareLedCount = finalLightIds.length; d.verbose = false; - //smoothing off - sc.smoothing.enable = false; + if (window.serverConfig.device.type !== d.type) { + //smoothing off, if new device + sc.smoothing = { enable: false }; + } } if (hueType == 'philipshueentertainment') { d.useEntertainmentAPI = true; d.hardwareLedCount = groupLights.length; - //smoothing on - sc.smoothing.enable = true; + if (window.serverConfig.device.type !== d.type) { + //smoothing on, if new device + sc.smoothing = { enable: true }; + } } window.serverConfig.device = d; @@ -1430,6 +1434,8 @@ function beginWizardYeelight() { window.serverConfig.leds = yeelightLedConfig; //LED device config + var currentDeviceType = window.serverConfig.device.type; + //Start with a clean configuration var d = {}; @@ -1454,9 +1460,10 @@ function beginWizardYeelight() { window.serverConfig.device = d; - //smoothing off - if (!(window.serverConfig.smoothing == null)) - window.serverConfig.smoothing.enable = false; + if (currentDeviceType !== d.type) { + //smoothing off, if new device + window.serverConfig.smoothing = { enable: false }; + } requestWriteConfig(window.serverConfig, true); resetWizard(); diff --git a/libsrc/hyperion/LinearColorSmoothing.cpp b/libsrc/hyperion/LinearColorSmoothing.cpp index 70cd0eef..d5850134 100644 --- a/libsrc/hyperion/LinearColorSmoothing.cpp +++ b/libsrc/hyperion/LinearColorSmoothing.cpp @@ -113,10 +113,8 @@ void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJson if (type == settings::type::SMOOTHING) { QJsonObject obj = config.object(); - if (enabled() != obj["enable"].toBool(true)) - { - setEnable(obj["enable"].toBool(true)); - } + + setEnable(obj["enable"].toBool(_enabled)); SmoothingCfg cfg(false, static_cast(obj[SETTINGS_KEY_SETTLING_TIME].toInt(DEFAULT_SETTLINGTIME)),