Closed Themicles closed 5 months ago
artnet.parse() returns OpCode::NA if parsing failed
I saw that in the code as I was looking through the library a few hours after I posted. I will close this out now and work on changes to my code. I typically don't like posting in Issues for what is just a question and not a found bug. Thank you.
Reopening as I've quickly realized my understanding of how the code works is incomplete. I am not sure I understand how to check the Return of artnet.parse().
My first instinct is:
if(artnet.parse() != NA)
But the compiler says NA isn't defined in this scope. Okay, so what is the definition of NA, 0x0000, so I tried:
if(artnet.parse() != 0x0000)
This produced:
Compilation error: no match for 'operator!=' (operand types are 'art_net::OpCode' and 'int')
Not at all understanding what the next code would mean, I attempted:
if(artnet.parse() != art_net::OpCode(0x0000))
Which compiles, but the code doesn't operate as expected.
Pasting my entire code in the next comment, built from the receive_fastled example
#include <FastLED.h> // include FastLED *before* Artnet
// Please include ArtnetWiFi.h to use Artnet on the platform
// which can use both WiFi and Ethernet
#include <ArtnetWiFi.h>
// this is also valid for other platforms which can use only WiFi
// #include <Artnet.h>
// WiFi stuff
const char* ssid = "ssid";
const char* pwd = "password";
//const IPAddress ip(10, 42, 0, 201);
//const IPAddress gateway(10, 42, 0, 1);
//const IPAddress subnet(255, 255, 255, 0);
ArtnetWiFiReceiver artnet;
uint8_t universe = 1; // 0 - 15
// FastLED
#define NUM_LEDS 2
CRGB leds[NUM_LEDS];
const uint8_t PIN_LED_DATA = 12;
int nDisconnectMessageSent = 0;
int nConnectedMessageSent = 0;
int nArtNetDisconnectNotice = 0;
void setup() {
Serial.begin(115200);
delay(2000);
FastLED.addLeds<NEOPIXEL, PIN_LED_DATA>(leds, NUM_LEDS);
// WiFi stuff
WiFi.begin(ssid, pwd);
// WiFi.config(ip, gateway, subnet);
Serial.println("Start");
//Check a few times for wifi connection before starting, allow to start without wifi after 24 checks
int nCheckCount = 0;
while((nCheckCount < 24) && (WiFi.status() != WL_CONNECTED)) {
Serial.print(".");
delay(500);
//Serial.print("Check Count=");
//Serial.println(nCheckCount);
nCheckCount++;
}
Serial.print(" WiFi check attempts = ");
Serial.println(nCheckCount);
if(WiFi.status() == WL_CONNECTED){
nDisconnectMessageSent = 0;
nConnectedMessageSent = 1;
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
}
artnet.begin();
// if Artnet packet comes to this universe, forward them to fastled directly
artnet.forwardArtDmxDataToFastLED(universe, leds, NUM_LEDS);
// this can be achieved manually as follows
// if Artnet packet comes to this universe, this function (lambda) is called
//artnet.subscribeArtDmxUniverse(universe, [&](const uint8_t* data, uint16_t size, const ArtDmxMetadata &metadata, const ArtNetRemoteInfo &remote) {
// // set led
// // artnet data size per packet is 512 max
// // so there is max 170 pixel per packet (per universe)
// Serial.println("Artnet packet found");
// for (size_t pixel = 0; pixel < NUM_LEDS; ++pixel) {
// size_t idx = pixel * 3;
// leds[pixel].r = data[idx + 0];
// leds[pixel].g = data[idx + 1];
// leds[pixel].b = data[idx + 2];
// }
// });
}
void loop() {
//Serial.print(".");
if(WiFi.status() != WL_CONNECTED) {
//Serial.print("-");
//Print not connected message ONCE
if(nDisconnectMessageSent != 1){
nDisconnectMessageSent = 1;
nConnectedMessageSent = 0;
Serial.println("Wifi not connected!");
Serial.println("Defaulting to internal code...");
delay(500);
}
// Turn the LED on, then pause
for(size_t pixel = 0; pixel < NUM_LEDS; ++pixel){
leds[pixel] = CRGB::Red;
FastLED.show();
delay(500);
// Now turn the LED off, then pause
leds[pixel] = CRGB::Black;
FastLED.show();
delay(500);
}
}
else if(artnet.parse() != art_net::OpCode(0x0000)){
//Serial.print("+");
//Print connected message ONCE
if(nConnectedMessageSent != 1){
nDisconnectMessageSent = 0;
nConnectedMessageSent = 1;
nArtNetDisconnectNotice = 0;
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
Serial.println("Parsing ArtNet data...");
delay(500);
}
//Is this even needed here after running it in the else if?
//artnet.parse(); // check if artnet packet has come and execute callback
}
else{
//Print notice that ArtNet packets are invalid despite WiFi being connected
if(nArtNetDisconnectNotice != 1){
nArtNetDisconnectNotice = 1;
Serial.println("WiFi is Connected but ArtNet packets are invalid");
}
}
FastLED.show();
}
Ah, artnet.parse()
returns the same value when no packet is received and the parse fails. I will add artnet::OpCode::ParseFailed
Added in v0.4.6 https://github.com/hideakitai/ArtNet/pull/102
Please use
if (artnet.parse() == artnet::OpCode::ParseFailed) {
// error handling
}
Added in v0.4.6 #102
Please use
if (artnet.parse() == artnet::OpCode::ParseFailed) { // error handling }
Using this exact code I am getting the following error even if I isolate and only run that code:
Compilation error: 'artnet' is not a class, namespace, or enumeration
Ah sorry art_net
Code compiles and mostly works, however even removing the ArtNet sender from the network does not end up triggering the ParseFailed state. Observed state of the LEDs is that they retain the last color values sent. Checking the terminal, the message that is supposed to be sent in:
else if(artnet.parse() == art_net::OpCode::ParseFailed){
//Serial.print("_");
//Print notice that ArtNet packets are invalid despite WiFi being connected
if(nArtNetDisconnectNotice != 1){
nArtNetDisconnectNotice = 1;
Serial.println("WiFi is Connected but ArtNet packets are invalid");
}
}
never appears.
Full code below:
#include <FastLED.h> // include FastLED *before* Artnet
// Please include ArtnetWiFi.h to use Artnet on the platform
// which can use both WiFi and Ethernet
#include <ArtnetWiFi.h>
// this is also valid for other platforms which can use only WiFi
// #include <Artnet.h>
// WiFi stuff
const char* ssid = "ssid";
const char* pwd = "pwd";
//const IPAddress ip(10, 42, 0, 201);
//const IPAddress gateway(10, 42, 0, 1);
//const IPAddress subnet(255, 255, 255, 0);
ArtnetWiFiReceiver artnet;
uint8_t universe = 1; // 0 - 15
// FastLED
#define NUM_LEDS 2
CRGB leds[NUM_LEDS];
const uint8_t PIN_LED_DATA = 12;
int nDisconnectMessageSent = 0;
int nConnectedMessageSent = 0;
int nArtNetDisconnectNotice = 0;
void setup() {
Serial.begin(115200);
delay(2000);
FastLED.addLeds<NEOPIXEL, PIN_LED_DATA>(leds, NUM_LEDS);
// WiFi stuff
WiFi.begin(ssid, pwd);
//WiFi.config(ip, gateway, subnet);
Serial.println("Start");
//Check a few times for wifi connection before starting, allow to start without wifi after 24 checks
int nCheckCount = 0;
while((nCheckCount < 24) && (WiFi.status() != WL_CONNECTED)) {
Serial.print(".");
delay(500);
//Serial.print("Check Count=");
//Serial.println(nCheckCount);
nCheckCount++;
}
Serial.print(" WiFi check attempts = ");
Serial.println(nCheckCount);
if(WiFi.status() == WL_CONNECTED){
nDisconnectMessageSent = 0;
nConnectedMessageSent = 1;
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
Serial.println("Parsing ArtNet data...");
}
artnet.begin();
// if Artnet packet comes to this universe, forward them to fastled directly
artnet.forwardArtDmxDataToFastLED(universe, leds, NUM_LEDS);
// this can be achieved manually as follows
// if Artnet packet comes to this universe, this function (lambda) is called
//artnet.subscribeArtDmxUniverse(universe, [&](const uint8_t* data, uint16_t size, const ArtDmxMetadata &metadata, const ArtNetRemoteInfo &remote) {
// // set led
// // artnet data size per packet is 512 max
// // so there is max 170 pixel per packet (per universe)
// Serial.println("Artnet packet found");
// for (size_t pixel = 0; pixel < NUM_LEDS; ++pixel) {
// size_t idx = pixel * 3;
// leds[pixel].r = data[idx + 0];
// leds[pixel].g = data[idx + 1];
// leds[pixel].b = data[idx + 2];
// }
// });
}
void loop() {
//Serial.print(".");
if(WiFi.status() != WL_CONNECTED) {
//Serial.print("-");
//Print not connected message ONCE
if(nDisconnectMessageSent != 1){
nDisconnectMessageSent = 1;
nConnectedMessageSent = 0;
Serial.println("Wifi not connected!");
Serial.println("Defaulting to internal code...");
delay(500);
}
// Turn the LED on, then pause
for(size_t pixel = 0; pixel < NUM_LEDS; ++pixel){
leds[pixel] = CRGB::Red;
FastLED.show();
delay(500);
// Now turn the LED off, then pause
leds[pixel] = CRGB::Black;
FastLED.show();
delay(500);
}
}
else if(artnet.parse() == art_net::OpCode::ParseFailed){
//Serial.print("_");
//Print notice that ArtNet packets are invalid despite WiFi being connected
if(nArtNetDisconnectNotice != 1){
nArtNetDisconnectNotice = 1;
Serial.println("WiFi is Connected but ArtNet packets are invalid");
}
}
else{
//Serial.print("+");
//Print connected message ONCE
if(nConnectedMessageSent != 1){
nDisconnectMessageSent = 0;
nConnectedMessageSent = 1;
nArtNetDisconnectNotice = 0;
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
Serial.println("Parsing ArtNet data...");
delay(500);
}
artnet.parse(); // check if artnet packet has come and execute callback
}
FastLED.show();
}
As you said before
Is there any kind of return I could be looking for if artnet packets fail to parse?
OpCode::ParseFailed
comes only if the parsing "failed". So if you remove the sender from network, it won't come because the packet is not received. In such situation, parse()
returns OpCode::NA
Edit: Updated the code for the OpCode changes in 0.5.0 Thanks for all of your help and the additions you've made to the code. I now have the code working as I want. When receiving ArtNet packets, even when fixtures are turned off in the lighting software, it does exactly as the lighting software tells it. If too many packets are missed, it switches to an error animation (currently). Or if WiFi never connected, or drops connection, it also runs the error animation. In all cases, when ideal conditions return, it returns to control of the lighting software over ArtNet.
Here's the full code. I have some cleanup work to do and need to take a look at what I could be doing more efficiently.
#include <FastLED.h> // include FastLED *before* Artnet
// Please include ArtnetWiFi.h to use Artnet on the platform
// which can use both WiFi and Ethernet
#include <ArtnetWiFi.h>
// this is also valid for other platforms which can use only WiFi
// #include <Artnet.h>
// WiFi stuff
const char* ssid = "ssid";
const char* pwd = "pwd";
//const IPAddress ip(10, 42, 0, 201);
//const IPAddress gateway(10, 42, 0, 1);
//const IPAddress subnet(255, 255, 255, 0);
ArtnetWiFiReceiver artnet;
uint8_t universe = 1; // 0 - 15
// FastLED
#define NUM_LEDS 2
CRGB leds[NUM_LEDS];
const uint8_t PIN_LED_DATA = 12;
int nDisconnectMessageSent = 0;
int nConnectedMessageSent = 0;
int nArtNetDisconnectNotice = 0;
int nArtNetCodeNATracker = 0;
int nMissinPacketThreshold = 225;
void setup() {
Serial.begin(115200);
delay(2000);
FastLED.addLeds<NEOPIXEL, PIN_LED_DATA>(leds, NUM_LEDS);
// WiFi stuff
WiFi.begin(ssid, pwd);
//WiFi.config(ip, gateway, subnet);
Serial.println("Start");
//Check a few times for wifi connection before starting, allow to start without wifi after 24 checks
int nCheckCount = 0;
while((nCheckCount < 24) && (WiFi.status() != WL_CONNECTED)) {
Serial.print(".");
delay(500);
//Serial.print("Check Count=");
//Serial.println(nCheckCount);
nCheckCount++;
}
Serial.print(" WiFi check attempts = ");
Serial.println(nCheckCount);
if(WiFi.status() == WL_CONNECTED){
nDisconnectMessageSent = 0;
nConnectedMessageSent = 1;
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
Serial.println("Parsing ArtNet data...");
nConnectedMessageSent = 1;
}
artnet.begin();
// if Artnet packet comes to this universe, forward them to fastled directly
artnet.forwardArtDmxDataToFastLED(universe, leds, NUM_LEDS);
// this can be achieved manually as follows
// if Artnet packet comes to this universe, this function (lambda) is called
//artnet.subscribeArtDmxUniverse(universe, [&](const uint8_t* data, uint16_t size, const ArtDmxMetadata &metadata, const ArtNetRemoteInfo &remote) {
// // set led
// // artnet data size per packet is 512 max
// // so there is max 170 pixel per packet (per universe)
// Serial.println("Artnet packet found");
// for (size_t pixel = 0; pixel < NUM_LEDS; ++pixel) {
// size_t idx = pixel * 3;
// leds[pixel].r = data[idx + 0];
// leds[pixel].g = data[idx + 1];
// leds[pixel].b = data[idx + 2];
// }
// });
}
void loop() {
//Serial.print(".");
if(WiFi.status() != WL_CONNECTED) {
Serial.print("-");
//Print not connected message ONCE per not-connected period
if(nDisconnectMessageSent != 1){
nDisconnectMessageSent = 1;
nConnectedMessageSent = 0;
Serial.println("Wifi not connected!");
Serial.println("Defaulting to internal code...");
//delay(500);
}
discoStatusAnim();
}
else if(artnet.parse() == art_net::OpCode::NoPacket){
//Serial.print("_");
nArtNetCodeNATracker++;
//Only run disconnect code after X consecutive NA codes
if(nArtNetCodeNATracker >= nMissinPacketThreshold){
//Serial.print("|");
//Print notice that ArtNet packets are invalid or missing despite WiFi being connected once until another condition exists
if(nArtNetDisconnectNotice != 1){
nConnectedMessageSent = 0;
nArtNetDisconnectNotice = 1;
Serial.println("WiFi is Connected but ArtNet packets are invalid or missing");
//Serial.println(nArtNetCodeNATracker);
}
discoStatusAnim();
}
//Serial.print(" - ");
//Serial.println(nArtNetCodeNATracker);
}
else{
//Serial.print("+");
if(nArtNetCodeNATracker >= nMissinPacketThreshold){
Serial.println("Missing ArtNet packets were at or over threshold. Attempting to resume");
}
nArtNetCodeNATracker = 0;
nArtNetDisconnectNotice = 0;
//Print connected message ONCE per reconnect
if(nConnectedMessageSent != 1){
nDisconnectMessageSent = 0;
nConnectedMessageSent = 1;
Serial.print("WiFi connected, IP = ");
Serial.println(WiFi.localIP());
Serial.println("Parsing ArtNet data...");
}
artnet.parse(); // check if artnet packet has come and execute callback
}
FastLED.show();
}
void discoStatusAnim(){
//Light 1 LED at a time, red
for(size_t pixel = 0; pixel < NUM_LEDS; ++pixel){
leds[pixel] = CRGB::Red;
FastLED.show();
delay(500);
// Now turn the LED off, then pause
leds[pixel] = CRGB::Black;
FastLED.show();
delay(500);
}
return;
}
Closing the issue now
@Themicles OpCodes are renamed for clarity in v0.5.0. Please take a look at it.
Thanks for the heads up. Updating my last code post to reflect this change
While I am sure I could detect extremely poor connections in some other ways, I feel like detecting bad artnet packets or completely missing ones might be a quicker way to get my code to hand over to internal animations until WiFi is strong enough again.
Is there any kind of return I could be looking for if artnet packets fail to parse? I looked through the readme and maybe missed it if its there. The reason I want to base my "disconnect detect" on the packets is to swap to an internal animation before what is sent over ArtNet is frozen too long.
Example of my tests:
Test 1: Turn off WiFI access point. Result 1: My existing code based on if(WiFi.status() == WL_CONNECTED) swaps to internal animations I set up, instantly.
Test 2: Walk away from WiFi access point until switching to internal animations occur. Result 2: Artnet animations freeze minutes before the ESP8266 "realizes" it has a bad or lost connection and disconnects. Walked out of the house to the opposite side of the house as the AP, and it finally took walking behind a large camper before it dropped. The Artnet driven LEDs froze before leaving the corner of the outside of the house.
My end goal is wireless devices that can default to an animation if not receiving from the Artnet network, but then resume Artnet control as people walk in and out of range at an outdoor venue.