From b8a3593792761ca74f43613af1647bb6d33603f2 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Mon, 13 Jul 2020 23:52:08 +0200 Subject: [PATCH] Added a REST-API to NodeMCU devices and added using it as an optional update-mode --- .../NodeMCU/NodeMCUUpdateMode.cs | 21 ++ .../NodeMCU/NodeMCUWS2812USBUpdateQueue.cs | 154 ++++++--- .../NodeMCU/NodeMCUWS281XDeviceDefinition.cs | 24 +- .../RGB.NET.Devices.WS281X.csproj | 1 + .../Sketches/RGB.NET_NodeMCU.ino | 295 ++++++++++++++++++ .../Sketches/RGB.NET_udp.ino | 210 ------------- .../WS281XDeviceProvider.cs | 7 +- 7 files changed, 457 insertions(+), 255 deletions(-) create mode 100644 RGB.NET.Devices.WS281X/NodeMCU/NodeMCUUpdateMode.cs create mode 100644 RGB.NET.Devices.WS281X/Sketches/RGB.NET_NodeMCU.ino delete mode 100644 RGB.NET.Devices.WS281X/Sketches/RGB.NET_udp.ino diff --git a/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUUpdateMode.cs b/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUUpdateMode.cs new file mode 100644 index 0000000..f20bd8e --- /dev/null +++ b/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUUpdateMode.cs @@ -0,0 +1,21 @@ +namespace RGB.NET.Devices.WS281X.NodeMCU +{ + /// + /// Contaisn a list of possible update-modes for NodeMCU-devices. + /// + // ReSharper disable once InconsistentNaming + public enum NodeMCUUpdateMode + { + /// + /// Updates through the HTTP-REST-API. + /// Slow, but reliable. + /// + Http, + + /// + /// Updates through a UDP-connection. + /// Fast, but might skip updates if the network connection is bad. + /// + Udp + } +} diff --git a/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS2812USBUpdateQueue.cs b/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS2812USBUpdateQueue.cs index cb4424e..f5feffe 100644 --- a/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS2812USBUpdateQueue.cs +++ b/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS2812USBUpdateQueue.cs @@ -1,7 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; -using System.Net; +using System.Net.Http; using System.Net.Sockets; +using System.Text; +using System.Text.RegularExpressions; using RGB.NET.Core; namespace RGB.NET.Devices.WS281X.NodeMCU @@ -13,94 +16,169 @@ namespace RGB.NET.Devices.WS281X.NodeMCU /// public class NodeMCUWS2812USBUpdateQueue : UpdateQueue { - #region Constants - - private static readonly byte UPDATE_COMMAND = 0x02; - - #endregion - #region Properties & Fields private readonly string _hostname; - private readonly UdpClient _udpClient; + private HttpClient _httpClient = new HttpClient(); + private UdpClient _udpClient; + private readonly Dictionary _dataBuffer = new Dictionary(); private readonly Dictionary _sequenceNumbers = new Dictionary(); + private readonly Action _sendDataAction; + #endregion #region Constructors /// /// Initializes a new instance of the class. + /// If this constructor is used UDP updates are disabled. /// /// The update trigger used by this queue. /// The hostname to connect to. - /// The port used by the web-connection. - public NodeMCUWS2812USBUpdateQueue(IDeviceUpdateTrigger updateTrigger, string hostname, int port) + public NodeMCUWS2812USBUpdateQueue(IDeviceUpdateTrigger updateTrigger, string hostname) : base(updateTrigger) { this._hostname = hostname; - _udpClient = new UdpClient(_hostname, port); - _udpClient.Connect(_hostname, port); + _sendDataAction = SendHttp; + } + + /// + /// Initializes a new instance of the class. + /// If this constructor is used UDP updates are enabled. + /// + /// The update trigger used by this queue. + /// The hostname to connect to. + /// The port used by the UDP-connection. + public NodeMCUWS2812USBUpdateQueue(IDeviceUpdateTrigger updateTrigger, string hostname, int udpPort) + : base(updateTrigger) + { + this._hostname = hostname; + + _udpClient = new UdpClient(); + EnableUdp(udpPort); + + _sendDataAction = SendUdp; } #endregion #region Methods + /// + protected override void OnStartup(object sender, CustomUpdateData customData) + { + base.OnStartup(sender, customData); + + ResetDevice(); + } + /// protected override void Update(Dictionary dataSet) { foreach (IGrouping channelData in dataSet.Select(x => (((int channel, int key))x.Key, x.Value)) .GroupBy(x => x.Item1.channel)) { - int channel = channelData.Key; - byte[] buffer = _dataBuffer[channel]; - - buffer[0] = GetSequenceNumber(channel); - buffer[1] = (byte)((channel << 4) | UPDATE_COMMAND); - int i = 2; - foreach ((byte _, byte r, byte g, byte b) in channelData.OrderBy(x => x.Item1.key) - .Select(x => x.Value.GetRGBBytes())) - { - buffer[i++] = r; - buffer[i++] = g; - buffer[i++] = b; - } - - Send(buffer); + byte[] buffer = GetBuffer(channelData); + _sendDataAction(buffer); } } + private void SendHttp(byte[] buffer) + { + string data = Convert.ToBase64String(buffer); + lock (_httpClient) _httpClient?.PostAsync(GetUrl("update"), new StringContent(data, Encoding.ASCII)).Wait(); + } + + private void SendUdp(byte[] buffer) + { + _udpClient?.Send(buffer, buffer.Length); + } + + private byte[] GetBuffer(IGrouping data) + { + int channel = data.Key; + byte[] buffer = _dataBuffer[channel]; + + buffer[0] = GetSequenceNumber(channel); + buffer[1] = (byte)channel; + int i = 2; + foreach ((byte _, byte r, byte g, byte b) in data.OrderBy(x => x.Item1.key) + .Select(x => x.Value.GetRGBBytes())) + { + buffer[i++] = r; + buffer[i++] = g; + buffer[i++] = b; + } + + return buffer; + } + internal IEnumerable<(int channel, int ledCount)> GetChannels() { - WebClient webClient = new WebClient(); - webClient.DownloadString($"http://{_hostname}/reset"); + string configString; + lock (_httpClient) configString = _httpClient.GetStringAsync(GetUrl("config")).Result; - int channelCount = int.Parse(webClient.DownloadString($"http://{_hostname}/channels")); - for (int channel = 1; channel <= channelCount; channel++) + configString = configString.Replace(" ", "") + .Replace("\r", "") + .Replace("\n", ""); + + //HACK DarthAffe 13.07.2020: Adding a JSON-Parser dependency just for this is not really worth it right now ... + MatchCollection channelMatches = Regex.Matches(configString, "\\{\"channel\":(?\\d+),\"leds\":(?\\d+)\\}"); + foreach (Match channelMatch in channelMatches) { - int ledCount = int.Parse(webClient.DownloadString($"http://{_hostname}/channel/{channel}")); - if (ledCount > 0) + int channel = int.Parse(channelMatch.Groups["channel"].Value); + int leds = int.Parse(channelMatch.Groups["leds"].Value); + if (leds > 0) { - _dataBuffer[channel] = new byte[(ledCount * 3) + 2]; + _dataBuffer[channel] = new byte[(leds * 3) + 2]; _sequenceNumbers[channel] = 0; - yield return (channel, ledCount); + yield return (channel, leds); } } } - private void Send(byte[] data) => _udpClient.Send(data, data.Length); + internal void ResetDevice() + { + lock (_httpClient) _httpClient.GetStringAsync(GetUrl("reset")).Wait(); + } + + private void EnableUdp(int port) + { + _httpClient.PostAsync(GetUrl("enableUDP"), new StringContent(port.ToString(), Encoding.UTF8, "application/json")).Result.Content.ReadAsStringAsync().Wait(); + _udpClient.Connect(_hostname, port); + } private byte GetSequenceNumber(int channel) { - byte sequenceNumber = (byte)((_sequenceNumbers[channel] + 1) % byte.MaxValue); + byte sequenceNumber = (byte)Math.Max(1, (_sequenceNumbers[channel] + 1) % byte.MaxValue); _sequenceNumbers[channel] = sequenceNumber; return sequenceNumber; } + /// + public override void Dispose() + { + lock (_httpClient) + { + base.Dispose(); + +#if NETSTANDARD + _udpClient?.Dispose(); +#endif + _udpClient = null; + + ResetDevice(); + _httpClient.Dispose(); + _httpClient = null; + } + } + + private string GetUrl(string path) => $"http://{_hostname}/{path}"; + #endregion } } diff --git a/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS281XDeviceDefinition.cs b/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS281XDeviceDefinition.cs index 14d5a05..f573eab 100644 --- a/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS281XDeviceDefinition.cs +++ b/RGB.NET.Devices.WS281X/NodeMCU/NodeMCUWS281XDeviceDefinition.cs @@ -2,6 +2,7 @@ // ReSharper disable UnusedMember.Global // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global +using System; using System.Collections.Generic; using RGB.NET.Core; @@ -22,9 +23,14 @@ namespace RGB.NET.Devices.WS281X.NodeMCU public string Hostname { get; } /// - /// Gets the port of the UDP connection. + /// Gets or sets the port of the UDP connection. /// - public int Port { get; } + public int Port { get; set; } = 1872; + + /// + /// Gets or sets the update-mode of the device. + /// + public NodeMCUUpdateMode UpdateMode { get; set; } /// /// Gets or sets the name used by this device. @@ -40,11 +46,11 @@ namespace RGB.NET.Devices.WS281X.NodeMCU /// Initializes a new instance of the class. /// /// The hostname to connect to. - /// The port of the UDP connection. - public NodeMCUWS281XDeviceDefinition(string hostname, int port = 1872) + /// The update mode of the device. + public NodeMCUWS281XDeviceDefinition(string hostname, NodeMCUUpdateMode updateMode = NodeMCUUpdateMode.Udp) { this.Hostname = hostname; - this.Port = port; + this.UpdateMode = updateMode; } #endregion @@ -54,7 +60,13 @@ namespace RGB.NET.Devices.WS281X.NodeMCU /// public IEnumerable CreateDevices(IDeviceUpdateTrigger updateTrigger) { - NodeMCUWS2812USBUpdateQueue queue = new NodeMCUWS2812USBUpdateQueue(updateTrigger, Hostname, Port); + NodeMCUWS2812USBUpdateQueue queue = UpdateMode switch + { + NodeMCUUpdateMode.Http => new NodeMCUWS2812USBUpdateQueue(updateTrigger, Hostname), + NodeMCUUpdateMode.Udp => new NodeMCUWS2812USBUpdateQueue(updateTrigger, Hostname, Port), + _ => throw new ArgumentOutOfRangeException() + }; + IEnumerable<(int channel, int ledCount)> channels = queue.GetChannels(); int counter = 0; foreach ((int channel, int ledCount) in channels) diff --git a/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj b/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj index d2ce907..c8a987d 100644 --- a/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj +++ b/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj @@ -64,6 +64,7 @@ + diff --git a/RGB.NET.Devices.WS281X/Sketches/RGB.NET_NodeMCU.ino b/RGB.NET.Devices.WS281X/Sketches/RGB.NET_NodeMCU.ino new file mode 100644 index 0000000..dc28c66 --- /dev/null +++ b/RGB.NET.Devices.WS281X/Sketches/RGB.NET_NodeMCU.ino @@ -0,0 +1,295 @@ +#define FASTLED_ESP8266_RAW_PIN_ORDER + +#include "FastLED.h" +#include +#include +#include +#include "base64.hpp" + +//#### CONFIGURATION #### + +// WLAN settings +const char* ssid = ""; // WLAN-network-name +const char* password = ""; // WLAN-password + +#define CHANNELS 4 // change this only if you add or remove channels in the implementation-part. To disable channels set them to 0 leds. + +// should not exceed 168 leds, since that results in the maximum paket size that is safe to transmit. Everything above could potentially be dropped. +// no more than 255 leds per channel (hard limit) +#define LEDS_CHANNEL_1 3 +#define LEDS_CHANNEL_2 0 +#define LEDS_CHANNEL_3 0 +#define LEDS_CHANNEL_4 0 + +#define PIN_CHANNEL_1 15 // D8 +#define PIN_CHANNEL_2 13 // D7 +#define PIN_CHANNEL_3 12 // D6 +#define PIN_CHANNEL_4 14 // D5 + +#define WEBSERVER_PORT 80 + +//####################### + +CRGB leds_channel_1[LEDS_CHANNEL_1]; +CRGB leds_channel_2[LEDS_CHANNEL_2]; +CRGB leds_channel_3[LEDS_CHANNEL_3]; +CRGB leds_channel_4[LEDS_CHANNEL_4]; + +ESP8266WebServer server(80); +WiFiUDP Udp; + +bool isUDPEnabled; +int udpPort; +byte incomingPacket[767]; // 255 (max leds) * 3 + 2 (header) +byte lastSequenceNumbers[CHANNELS]; + +bool checkSequenceNumber(int channel, byte currentSequenceNumber) +{ + bool isValid = (currentSequenceNumber > lastSequenceNumbers[channel]) || ((lastSequenceNumbers[channel] > 200) && (currentSequenceNumber < 50)); + if(isValid) + { + lastSequenceNumbers[channel] = currentSequenceNumber; + } + return isValid; +} + +void processUDP() +{ + int packetSize = Udp.parsePacket(); + if (packetSize) + { + // receive incoming UDP packets + byte sequenceNumber = Udp.read(); + byte channel = Udp.read(); + if(checkSequenceNumber(channel, sequenceNumber)) + { + switch(channel) + { + case 1: // set leds of channel 1 + Udp.read((uint8_t*)leds_channel_1, (LEDS_CHANNEL_1 * 3)); + FastLED.show(); + break; + + // ### channel 2 ### + case 2: // set leds of channel 2 + Udp.read((uint8_t*)leds_channel_2, (LEDS_CHANNEL_2 * 3)); + FastLED.show(); + break; + + // ### channel 3 ### + case 3: // set leds of channel 3 + Udp.read((uint8_t*)leds_channel_3, (LEDS_CHANNEL_3 * 3)); + FastLED.show(); + break; + + // ### channel 4 ### + case 4: // set leds of channel 4 + Udp.read((uint8_t*)leds_channel_4, (LEDS_CHANNEL_4 * 3)); + FastLED.show(); + break; + + // ### default ### + default: + break; + } + } + } +} + +void handleRoot() +{ + String infoSite = (String)"\ + \ + RGB.NET\ + \ + \ +

RGB.NET

\ + This device is currently running the NodeMCU WS281X RGB.NET-Sketch.
\ +
\ + Check https://github.com/DarthAffe/RGB.NET for more info and the latest version of this sketch.
\ +
\ +

Configuration:

\ + UDP:\ " + (isUDPEnabled ? ((String)"enabled (" + udpPort + ")") : "disabled") + "
\ +
\ + Channel 1
\ + Leds: " + LEDS_CHANNEL_1 + "
\ + Pin: " + PIN_CHANNEL_1 + "
\ +
\ + Channel 2
\ + Leds: " + LEDS_CHANNEL_2 + "
\ + Pin: " + PIN_CHANNEL_2 + "
\ +
\ + Channel 4
\ + Leds: " + LEDS_CHANNEL_3 + "
\ + Pin: " + PIN_CHANNEL_3 + "
\ +
\ + Channel 4
\ + Leds: " + LEDS_CHANNEL_4 + "
\ + Pin: " + PIN_CHANNEL_4 + "
\ +
\ + \ +"; + + server.send(200, "text/html", infoSite); +} + +void handleConfig() +{ + String config = (String)"{\ + \"channels\": [\ + {\ + \"channel\": 1,\ + \"leds\": " + LEDS_CHANNEL_1 + "\ + },\ + {\ + \"channel\": 2,\ + \"leds\": " + LEDS_CHANNEL_2 + "\ + },\ + {\ + \"channel\": 3,\ + \"leds\": " + LEDS_CHANNEL_3 + "\ + },\ + {\ + \"channel\": 4,\ + \"leds\": " + LEDS_CHANNEL_4 + "\ + }\ + ]\ +}"; + + server.send(200, "application/json", config); +} + +void handleEnableUDP() +{ + if(isUDPEnabled) + { + Udp.stop(); + } + + udpPort = server.arg(0).toInt(); + + Udp.begin(udpPort); + isUDPEnabled = true; + + server.send(200, "text/html", ""); +} + +void handleDisableUDP() +{ + if(isUDPEnabled) + { + Udp.stop(); + isUDPEnabled = false; + } + + server.send(200, "text/html", ""); +} + +void handleReset() +{ + for(int i = 0; i < CHANNELS; i++) + { + lastSequenceNumbers[i] = 0; + } + + for(int i = 0; i < LEDS_CHANNEL_1; i++) + { + leds_channel_1[i] = CRGB::Black; + } + + for(int i = 0; i < LEDS_CHANNEL_2; i++) + { + leds_channel_2[i] = CRGB::Black; + } + + for(int i = 0; i < LEDS_CHANNEL_3; i++) + { + leds_channel_3[i] = CRGB::Black; + } + + for(int i = 0; i < LEDS_CHANNEL_4; i++) + { + leds_channel_4[i] = CRGB::Black; + } + + FastLED.show(); + + server.send(200, "text/html", ""); +} + +void handleUpdate() +{ + unsigned int dataLength = decode_base64((unsigned char*)server.arg(0).c_str(), incomingPacket); + + byte channel = (byte)incomingPacket[1]; + switch(channel) + { + case 1: // set leds of channel 1 + memcpy((uint8_t*)leds_channel_1, &incomingPacket[2], (LEDS_CHANNEL_1 * 3)); + FastLED.show(); + break; + + // ### channel 2 ### + case 2: // set leds of channel 2 + memcpy((uint8_t*)leds_channel_2, &incomingPacket[2], (LEDS_CHANNEL_2 * 3)); + FastLED.show(); + break; + + // ### channel 3 ### + case 3: // set leds of channel 3 + memcpy((uint8_t*)leds_channel_3, &incomingPacket[2], (LEDS_CHANNEL_3 * 3)); + FastLED.show(); + break; + + // ### channel 4 ### + case 4: // set leds of channel 4 + memcpy((uint8_t*)leds_channel_4, &incomingPacket[2], (LEDS_CHANNEL_4 * 3)); + FastLED.show(); + break; + + // ### default ### + default: + break; + } + + server.send(200, "text/html", ""); +} + +void setup() +{ + if(LEDS_CHANNEL_1 > 0) { FastLED.addLeds(leds_channel_1, LEDS_CHANNEL_1); } + if(LEDS_CHANNEL_2 > 0) { FastLED.addLeds(leds_channel_2, LEDS_CHANNEL_2); } + if(LEDS_CHANNEL_3 > 0) { FastLED.addLeds(leds_channel_3, LEDS_CHANNEL_3); } + if(LEDS_CHANNEL_4 > 0) { FastLED.addLeds(leds_channel_4, LEDS_CHANNEL_4); } + + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) + { + delay(500); + } + + delay(100); + + server.on("/", handleRoot); + server.on("/config", handleConfig); + server.on("/enableUDP", handleEnableUDP); + server.on("/disableUDP", handleDisableUDP); + server.on("/reset", handleReset); + server.on("/update", handleUpdate); + server.onNotFound(handleRoot); + + server.begin(); + + handleReset(); +} + +void loop() +{ + server.handleClient(); + + if(isUDPEnabled) + { + processUDP(); + } +} + \ No newline at end of file diff --git a/RGB.NET.Devices.WS281X/Sketches/RGB.NET_udp.ino b/RGB.NET.Devices.WS281X/Sketches/RGB.NET_udp.ino deleted file mode 100644 index 91f03d2..0000000 --- a/RGB.NET.Devices.WS281X/Sketches/RGB.NET_udp.ino +++ /dev/null @@ -1,210 +0,0 @@ -#define FASTLED_ESP8266_RAW_PIN_ORDER - -#include "FastLED.h" -#include -#include - -//#### CONFIGURATION #### - -// WLAN settings -const char* ssid = ""; // WLAN-network-name -const char* password = ""; // WLAN-password - -#define CHANNELS 4 // change this only if you add or remove channels in the implementation-part. To disable channels set them to 0 leds. - -// should not exceed 168 leds, since that results in the maximum paket size that is safe to transmit. Everything above could potentially be dropped. -// no more than 255 leds per channel (hard limit) -#define LEDS_CHANNEL_1 3 -#define LEDS_CHANNEL_2 0 -#define LEDS_CHANNEL_3 0 -#define LEDS_CHANNEL_4 0 - -#define PIN_CHANNEL_1 15 // D8 -#define PIN_CHANNEL_2 13 // D7 -#define PIN_CHANNEL_3 12 // D6 -#define PIN_CHANNEL_4 14 // D5 - -#define PORT 1872 // if changed needs to be configured in RGB.NET (default: 1872) - -#define WEBSERVER_PORT 80 - -//####################### - -CRGB leds_channel_1[LEDS_CHANNEL_1]; -CRGB leds_channel_2[LEDS_CHANNEL_2]; -CRGB leds_channel_3[LEDS_CHANNEL_3]; -CRGB leds_channel_4[LEDS_CHANNEL_4]; - -WiFiServer server(WEBSERVER_PORT); -WiFiUDP Udp; - -byte incomingPacket[767]; // 255 (max leds) * 3 + 2 (header) -byte lastSequenceNumbers[CHANNELS]; - -String header; - -void setup() { - if(LEDS_CHANNEL_1 > 0) { FastLED.addLeds(leds_channel_1, LEDS_CHANNEL_1); } - if(LEDS_CHANNEL_2 > 0) { FastLED.addLeds(leds_channel_2, LEDS_CHANNEL_2); } - if(LEDS_CHANNEL_3 > 0) { FastLED.addLeds(leds_channel_3, LEDS_CHANNEL_3); } - if(LEDS_CHANNEL_4 > 0) { FastLED.addLeds(leds_channel_4, LEDS_CHANNEL_4); } - - for(int i = 0; i < CHANNELS; i++) - { - lastSequenceNumbers[i] = 255; - } - - WiFi.begin(ssid, password); - while (WiFi.status() != WL_CONNECTED) - { - delay(500); - } - delay(100); - - Udp.begin(PORT); - server.begin(); -} - -bool checkSequenceNumber(int channel, byte currentSequenceNumber) -{ - bool isValid = (currentSequenceNumber > lastSequenceNumbers[channel]) || ((lastSequenceNumbers[channel] > 200) && (currentSequenceNumber < 50)); - if(isValid) - { - lastSequenceNumbers[channel] = currentSequenceNumber; - } - return isValid; -} - -void loop() { - // Web client - WiFiClient client = server.available(); - if (client) - { - String currentLine = ""; - while (client.connected()) - { - if (client.available()) - { - char c = client.read(); - header += c; - if (c == '\n') { - if (currentLine.length() == 0) { - client.println("HTTP/1.1 200 OK"); - client.println("Content-type:text/html"); - client.println("Connection: close"); - client.println(); - - if (header.indexOf("GET /reset") >= 0) - { - for(int i = 0; i < CHANNELS; i++) - { - lastSequenceNumbers[i] = 255; - } - for(int i = 0; i < LEDS_CHANNEL_1; i++) - { - leds_channel_1[i] = CRGB::Black; - } - for(int i = 0; i < LEDS_CHANNEL_2; i++) - { - leds_channel_2[i] = CRGB::Black; - } - for(int i = 0; i < LEDS_CHANNEL_3; i++) - { - leds_channel_3[i] = CRGB::Black; - } - for(int i = 0; i < LEDS_CHANNEL_4; i++) - { - leds_channel_4[i] = CRGB::Black; - } - FastLED.show(); - } - else if (header.indexOf("GET /channels") >= 0) - { - client.println(CHANNELS); - } - else if (header.indexOf("GET /channel/1") >= 0) - { - client.println(LEDS_CHANNEL_1); - } - else if (header.indexOf("GET /channel/2") >= 0) - { - client.println(LEDS_CHANNEL_2); - } - else if (header.indexOf("GET /channel/3") >= 0) - { - client.println(LEDS_CHANNEL_3); - } - else if (header.indexOf("GET /channel/4") >= 0) - { - client.println(LEDS_CHANNEL_4); - } - client.println(); - - break; - } - else - { - currentLine = ""; - } - } - else if (c != '\r') - { - currentLine += c; - } - } - } - header = ""; - client.stop(); - } - - // Color update - int packetSize = Udp.parsePacket(); - if (packetSize) - { - // receive incoming UDP packets - byte sequenceNumber = Udp.read(); - byte command = Udp.read(); - switch(command) - { - // ### channel 1 ### - case 0x12: // set leds of channel 1 - if(checkSequenceNumber(0, sequenceNumber)) - { - Udp.read(((uint8_t*)leds_channel_1), (LEDS_CHANNEL_1 * 3)); - FastLED.show(); - } - break; - - // ### channel 2 ### - case 0x22: // set leds of channel 2 - if(checkSequenceNumber(1, sequenceNumber)) - { - Udp.read(((uint8_t*)leds_channel_2), (LEDS_CHANNEL_2 * 3)); - FastLED.show(); - } - break; - - // ### channel 3 ### - case 0x32: // set leds of channel 3 - if(checkSequenceNumber(2, sequenceNumber)) - { - Udp.read(((uint8_t*)leds_channel_3), (LEDS_CHANNEL_3 * 3)); - FastLED.show(); - } - break; - - // ### channel 4 ### - case 0x42: // set leds of channel 4 - if(checkSequenceNumber(3, sequenceNumber)) - { - Udp.read(((uint8_t*)leds_channel_4), (LEDS_CHANNEL_4 * 3)); - FastLED.show(); - } - break; - - // ### default ### - default: - break; - } - } -} diff --git a/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs b/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs index 89ad1cc..3875cf4 100644 --- a/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs +++ b/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using RGB.NET.Core; +using RGB.NET.Devices.WS281X.NodeMCU; namespace RGB.NET.Devices.WS281X { @@ -105,7 +106,11 @@ namespace RGB.NET.Devices.WS281X /// public void ResetDevices() - { } + { + foreach (IRGBDevice device in Devices) + if (device is NodeMCUWS2812USBDevice nodemcuDevice) + nodemcuDevice.UpdateQueue.ResetDevice(); + } /// public void Dispose()