Lightning, data structures and wireless transmissions

Let me start with the TL;DR:
My project simulates lightning strikes outside a window using LED strips and panels. The "main" board blinks attached LED strips via a MOSFET, the other "remote" board is 10' away and blinks a similar set of LEDs via MOSFET. The first board randomly generates an on/off blink sequence to simulate lightning and both boards need to flash their respective LED strips using the same data. A small amount of out of sync is acceptable (no more than 200ms), due to data transmission/decode time.

I have previously attempted just using a wireless turn on / turn off signal from the main board to the remote one, but occasionally the remote side has not received the "off" command (due to RF interference, main board software crash, etc) and left the LEDs on, something most undesirable in a haunted house scenario!

This has been driving me up a wall for weeks now... I'm hoping someone here can point me in the right direction before I claw all my hair out. :wink:

Here's the project so far:

  • Two ESP32 dev boards (using for convenience of ESP-NOW and a web interface for the user on the control board, but using NRF24L01 or "generic" 315/433mhz radios is also equally acceptable)
  • The flash sequence runs randomly every 3-6 minutes or by button push on the main board with the details randomly generated each time.
  • The sequence needs to run simultaneously on the local/main board and the second/third/fourth/etc boards.
  • The sequence is a minimum of a single flash up to a maximum of 5 flashes.
  • The LEDS are turned on for random(100, 1000) ms, then turned off for random(100, 1000) ms, repeated random(1, 5) times as determined by the main board.

A sample in CSV format would look like "3,209,587,228,319,708,702"

There are 3 flashes for this sequence:
LEDs on for 209ms then off for 587ms
LEDs on for 228ms then off for 319ms
LEDs on for 708ms then off for 702ms*

(* The last 702ms off is irrelevant as the next "lightning strike" won't happen for another 3+ minutes, it's just easier to make a for loop with both on and off values)

It works beautifully on the local board with 24v cool white LEDs turned on and off with a MOSFET. I haven't found a way to send the data block to the remote boards in a way that can handle a command sequence that has a variable number of parameters based on the value of the first parameter sent...

I've been messing around with the ESP-NOW auto-pairing examples from RandomNerdTutorials, and there's a section where the variable/struct used is based on a parameter of the incoming data packet. Those packets have a finite number of parameters so I created a struct with the "maximum" amount of data for a lightning simulation and some "extras" for other remote board types eventually. The first 3 elements will be common to all data blocks.

enum MessageType {PAIRING, DATA, LIGHTNING, RELAY, MP3};

typedef struct struct_lightning {       // Define LIGHTNING data format
  uint8_t msgType; // this is a LIGHTNING packet, relay and sound effects later
  uint8_t group;   // The board's group ID (1 = lightning LEDs, 2 = relays, 3 = sound effects, etc)
  uint8_t address; // The board's individual address (0 = broadcast)
  uint8_t flashes; // The number of flashes in the sequence 1-5
  uint16_t on1;  uint16_t off1;
  uint16_t on2;  uint16_t off2;
  uint16_t on3;  uint16_t off3;
  uint16_t on4;  uint16_t off4;
  uint16_t on5;  uint16_t off5; // I'm resisting the temptation to add another pair so this doesn't end with an index value of [13] ;)
} struct_lightning;

struct_lightning lightningData;

This works for getting all the data to the remote side, but...

int lastPair = 4 + (lightningData.flashes * 2) - 2; // Set the last element index pair based on the number of flashes specified
// lastPair = 4 + ( 3 * 2 ) - 2 :  3 flashes, [4] is the start, [8]/[9] is the last on/off pair
// lastPair = 4 + ( 5 * 2 ) - 2 :  5 flashes, [4] is the start, [12]/[13] is the last on/off pair

for (int i = 4 ; i <= lastPair ; i + 2) {  // First pair starts at element [4] of the struct, then to 6, 8, etc.
  digitalWrite(LEDpin, HIGH);
  delay(lightningData.flashes[i]); // Wait for [i] ms with the LEDs on
  digitalWrite(LEDpin, LOW);
  delay(lightningData.flashes[i + 1]); // Read the companion to the previous element and wait
}

...I'm finding you can't address a struct by index (!!??!)...

In function 'void generateLightning()':
remote:139:34: error: expected unqualified-id before '[' token
     Serial.println(lightningData.[i]);
                                  ^

So how do I tell the loop to only run "lightningData.flashes" times and read lightningData.on1, lightningData.off1, lightningData.on2, lightningData.off2, etc?

Is there something really obvious that I'm missing? Just going wired would be just fine if our house wasn't 3 floors. :wink:

Am I reading it correctly that you wish to send variable length messages over ESP-NOW?
if so could you give a few examples?
I have send variable length arrays (integers, floats, etc) over ESP-NOW

this post is an example of sending different data types

No, not different data types - the struct already does that using 8 and 16 bit unsigned integers.

The first number indicates the number of data pairs for the remote to expect:
(using CSV format for clarity)
If sending 3 pairs: 3,209,587,228,319,708,702
If sending 5 pairs: 5,232,493,469,699,233,625,501,555,242,403,
If sending 2 pairs: 2,562,360,470,776
If sending 4 pairs: 4,478,439,397,578,796,738,323,223
If sending 1 pair: 1,603,515

That's not the issue. The issue is iterating through a struct by index, not by member name (i.e. myStruct[1] and not myStruct.memberName1), or by using some other similar way of getting variable size blocks from one to another.

In my code above there is a struct:

typedef struct struct_lightning {       // Define LIGHTNING data format
  uint8_t msgType; // this is a LIGHTNING packet, relay and sound effects later
  uint8_t group;   // The board's group ID (1 = lightning LEDs, 2 = relays, 3 = sound effects, etc)
  uint8_t address; // The board's individual address (0 = broadcast)
  uint8_t flashes; // The number of flashes in the sequence 1-5
  uint16_t on1;  uint16_t off1;
  uint16_t on2;  uint16_t off2;
  uint16_t on3;  uint16_t off3;
  uint16_t on4;  uint16_t off4;
  uint16_t on5;  uint16_t off5;
} struct_lightning;

Having 3 defined pairs would result in:

(CSV equivalent to 3,209,587,228,319,708,702) 

lightningData.msgType = 1
lightningData.group = 1
lightningData.address = 1
lightningData.flashes = 3
lightningData.on1 = 209
lightningData.off1 = 587
lightningData.on2 = 228
lightningData.off2 = 319
lightningData.on3 = 708
lightningData.off3 = 702

Having 4 defined pairs would result in:

(CSV equivalent to 4,209,587,228,319,708,702,360,500)

lightningData.msgType = 1
lightningData.group = 1
lightningData.address = 1
lightningData.flashes = 3
lightningData.on1 = 209
lightningData.off1 = 587
lightningData.on2 = 228
lightningData.off2 = 319
lightningData.on3 = 708
lightningData.off3 = 702
lightningData.on4 = 360
lightningData.off4 = 500

Having 1 defined pair would result in:

(CSV equivalent to 1,209,587)

lightningData.msgType = 1
lightningData.group = 1
lightningData.address = 1
lightningData.flashes = 3
lightningData.on1 = 209
lightningData.off1 = 587

The number of pairs of data (on and off times) varies between 1 and 5. Some transmissions will only have one par. Some will have 5. Most will have between 2 and 4.

Essentially I need to create, transmit and receive dynamic data blocks with different quantities of parameters which are not known until the function is called.

Why don’t you send an array of unsigned int and the size of the array or just the ascii csv text terminated by a new line?

Otherwise change the structure to be

const byte maxFlash = 5;
struct Lightning {       // Define Lightning data type
  uint8_t msgType;       // this is a LIGHTNING packet, relay and sound effects later
  uint8_t group;         // The board's group ID (1 = lightning LEDs, 2 = relays, 3 = sound effects, etc)
  uint8_t address;       // The board's individual address (0 = broadcast)
  uint8_t flashes;       // The number of flashes in the sequence 1-maxFlash
  uint16_t on[maxFlash];
  uint16_t off[maxFlash];
};

Then you have arrays you can iterate over for on and off

1 Like

this transmits a variable size int array

// ESP-NOW transmit variable sized arrays

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x24,0x62,0xAB,0xE0,0x64,0x54};

esp_now_peer_info_t peerInfo;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
 
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  static int data1[]={1,-2,3,-4}, 
      data2[]={5,6,-7,8,9,-10,11,12,-13,14}, 
      data3[]={5009,-6000,10095,-25000};
   // Send message via ESP-NOW
  esp_now_send(broadcastAddress, (uint8_t *) &data1, sizeof(data1));
  esp_now_send(broadcastAddress, (uint8_t *) &data2, sizeof(data2));
  esp_now_send(broadcastAddress, (uint8_t *) &data3, sizeof(data3));
  data1[0]+=1;
  data2[0]+=8;
  data3[0]+=300;
  
  delay(10000);
}

this receives the array and displays it

// ESP-NOW transmit variable sized arrays

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  int data[100];
  memcpy(data, incomingData, len);
  Serial.print("Bytes received: ");
  Serial.print(len);
  Serial.print(" Integers received: ");
  Serial.print(':');
  for(int i=0;i<len/sizeof(int);i++) {
    Serial.print(' ');Serial.print(data[i]); 
  }
Serial.println();
}

 
void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("ESP32 Board MAC Address:  ");
  Serial.println(WiFi.macAddress());

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() {

}

a run gives

ESP32 Board MAC Address:  24:62:AB:E0:64:54
Bytes received: 16 Integers received: : 1 -2 3 -4
Bytes received: 40 Integers received: : 5 6 -7 8 9 -10 11 12 -13 14
Bytes received: 16 Integers received: : 5009 -6000 10095 -25000
Bytes received: 16 Integers received: : 2 -2 3 -4
Bytes received: 40 Integers received: : 13 6 -7 8 9 -10 11 12 -13 14
Bytes received: 16 Integers received: : 5309 -6000 10095 -25000
Bytes received: 16 Integers received: : 3 -2 3 -4
Bytes received: 40 Integers received: : 21 6 -7 8 9 -10 11 12 -13 14
Bytes received: 16 Integers received: : 5609 -6000 10095 -25000
Bytes received: 16 Integers received: : 4 -2 3 -4
Bytes received: 40 Integers received: : 29 6 -7 8 9 -10 11 12 -13 14
Bytes received: 16 Integers received: : 5909 -6000 10095 -25000
Bytes received: 16 Integers received: : 5 -2 3 -4
Bytes received: 40 Integers received: : 37 6 -7 8 9 -10 11 12 -13 14
Bytes received: 16 Integers received: : 6209 -6000 10095 -25000
Bytes received: 16 Integers received: : 6 -2 3 -4
Bytes received: 40 Integers received: : 45 6 -7 8 9 -10 11 12 -13 14
Bytes received: 16 Integers received: : 6509 -6000 10095 -25000

You are not understanding the issue, or at least you're not looking at the data structure. My code is based off of ESP-NOW examples from Rui Santos - in this case the auto-pairing version that deals with environmental data.

The problem is processing the data after it has been received on the far end.

Using this for block:

for (int i = 1 ; i <= 5 ; i++) { 
  digitalWrite(LEDpin, HIGH);
  delay(lightningData.flashes[i]);
  digitalWrite(LEDpin, LOW);
  delay(lightningData.flashes[i]);
}

Results in this failure to compile:

In function 'void generateLightning()':
remote:139:34: error: expected unqualified-id before '[' token
     Serial.println(lightningData.[i]);
                                  ^

I need to iterate through the data but limit the progression based on the value of lightningData.flashes. Here's a fully loaded version that would transmit correctly, but not work as needed:

lightningData.flashes = 3
lightningData.on1 = 209
lightningData.off1 = 587
lightningData.on2 = 228
lightningData.off2 = 319
lightningData.on3 = 708
lightningData.off3 = 702
lightningData.on4 = 29336
lightningData.off4 = 24030
lightningData.on5 = 43536
lightningData.off5 = 48690

Without limiting the data reading to 3 pairs (lightningData.flashes), after the wanted flashes happen the lights will then stay on for 29.336 seconds, off for 24.030 seconds, then on again for 43.536 seconds, then hold them off for 48.690 seconds before accepting a new sequence.

How can I use a for loop, or something similar, to go through and parse the data received, without using the struct member name, but the index instead?

The struct uses uint8_t for data packet types, addresses, and commands as they will not have more than 255 possible items for each. Maxing out uint8_t would mean I have 65,025 receivers that can do 255 different functions... it's incredibly unlikely I'll have much more than the lightning strings, some relay closures to trigger fans or button-controlled props, a fog machine and an MP3 player, even if I set this up in a fully interactive haunted house for a community theater.

It also uses uint16_t for the length of the flashes, but future packet types will need to incorporate char and bool (file name to play, and if (isPlaying > 0) { return(0); } else { playSound(songFileName);} ) to accommodate MP3 based sound effects on a separate SOC. My understanding is that the only way to do this kind of a data block transmission is with a struct / typedef.

The original goal in keeping the memory use extremely low was because the Nordic NRF24L01 had a limit of 32 bytes (and the $1 433mhz radios limit to 27 if I remember right). Ideally I'd like to use RF24mesh or RadioHead compatible radios rather than have to use an ESP32 for every other new prop and light my roommate buys for Halloween. :wink:

I couldn't use a CSV string because the original incarnation of this project was going to use the cheap 433mhz ASK radios which I believe is limited to 27 bytes, then I tried the NRF24L01, but that's limited to 32 bytes.

Even going completely numeric for commands and parameters I exceeded the maximum data size for transmission.

I'll tinker with the other example you gave, never thought about two uint16_t based arrays in parallel instead of individual elements...

That's why I came here to ask! It's a little after 4am, so I need to go home and get to bed. Thanks for the help, I'll update here after I've tried your solution. :slight_smile:

Thanks!

why not use arrays for your on/off values
you can then index them using the value of lightningData.flashes
e.g.

struct struct_lightning {       // Define LIGHTNING data format
  uint8_t msgType; // this is a LIGHTNING packet, relay and sound effects later
  uint8_t group;   // The board's group ID (1 = lightning LEDs, 2 = relays, 3 = sound effects, etc)
  uint8_t address; // The board's individual address (0 = broadcast)
  uint8_t flashes; // The number of flashes in the sequence 1-5
  uint16_t on[5];  uint16_t off[5];
} lightningData;

void setup() {
  Serial.begin(115200);
  lightningData.msgType = 1;
  lightningData.group = 1;
  lightningData.address = 1;
  lightningData.flashes = 3;
  lightningData.on[0] = 209;
  lightningData.off[0] = 587;
  lightningData.on[1] = 228;
  lightningData.off[1] = 319;
  lightningData.on[2] = 708;
  lightningData.off[2] = 702;
  Serial.print("\nlightningData.flashes "); Serial.println(lightningData.flashes);
  for (int i = 0; i < lightningData.flashes; i++) {
    Serial.print("on "); Serial.print(lightningData.on[i]);
    Serial.print(" off "); Serial.println(lightningData.off[i]);
  }

  lightningData.msgType = 1;
  lightningData.group = 1;
  lightningData.address = 1;
  lightningData.flashes = 1;
  lightningData.on[0] = 310;
  lightningData.off[0] = 650;
  Serial.print("\nlightningData.flashes "); Serial.println(lightningData.flashes);
  for (int i = 0; i < lightningData.flashes; i++) {
    Serial.print("on "); Serial.print(lightningData.on[i]);
    Serial.print(" off "); Serial.println(lightningData.off[i]);
  }
}

void loop() {}

when run

lightningData.flashes 3
on 209 off 587
on 228 off 319
on 708 off 702

lightningData.flashes 1
on 310 off 650

So.... I set up the structures as suggested with two arrays, one for on and one for off.

// On the controller
const byte maxFlashes = 5;

typedef struct struct_lightning {       // Define Lightning data type
  uint8_t msgType;       // this is a LIGHTNING packet, relay and sound effects later
  uint8_t group;         // The board's group ID (1 = lightning LEDs, 2 = relays, 3 = sound effects, etc)
  uint8_t address;       // The board's individual address (0 = broadcast)
  uint8_t flashes;       // The number of flashes in the sequence 1-maxFlash
  uint16_t on[maxFlashes];
  uint16_t off[maxFlashes];
};

struct_lightning lightningData;

enum MessageType { PAIRING, DATA, LIGHTNING, RELAY };

void lightningShow() {
  lightningData.msgType = LIGHTNING;
  lightningData.group = random(0,250);
  lightningData.address = random(0,250);
  lightningData.flashes = random(2, maxFlashes);
  for (int i = 0; i < lightningData.flashes; i++) {
    lightningData.on[i] = random(200, 900);
    lightningData.off[i] = random(200, 900);
  }

  Serial.print("lightningData.msgType = ");
  Serial.println(lightningData.msgType);
  Serial.print("lightningData.group = ");
  Serial.println(lightningData.group);
  Serial.print("lightningData.address = ");
  Serial.println(lightningData.address);
  Serial.print("lightningData.flashes = ");
  Serial.println(lightningData.flashes);

  for (int i = 0; i < lightningData.flashes; i++) {
    Serial.print("Step ");
    Serial.print(i);
    Serial.print(":  ON ");
    Serial.print(lightningData.on[i]);
    Serial.print("    OFF ");
    Serial.println(lightningData.off[i]);
  }

  esp_now_send(NULL, (uint8_t *)&lightningData, sizeof(lightningData));

}  // lightningShow()

void loop() {
  static unsigned long lastEventTime = millis();
  static const unsigned long EVENT_INTERVAL_MS = 5000;
  if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {
    // Do something every 5 seconds
    lastEventTime = millis();
    Serial.println("Sending lightningData packet");
    lightningShow();
  }
}

Controller Serial Monitor:

23:39:56.206 -> Sending lightningData packet
23:39:56.206 -> lightningData.msgType = 2
23:39:56.206 -> lightningData.group = 101
23:39:56.206 -> lightningData.address = 212
23:39:56.206 -> lightningData.flashes = 3
23:39:56.206 -> Step 0:  ON 226    OFF 291
23:39:56.247 -> Step 1:  ON 671    OFF 405
23:39:56.247 -> Step 2:  ON 898    OFF 618

Looks good - the serial.print statements are generated from the struct data, not printed as the numbers are generated. This looks good!

// On the receiver:
void lightningShow() {
  Serial.println("lightningShow()");
  Serial.print("lightningData.flashes = ");
  Serial.println(lightningData.flashes);

  for (int i = 0; i < lightningData.flashes; i++) {
    Serial.print("Step ");
    Serial.print(i);
    Serial.print(":  ON ");
    Serial.print(lightningData.on[i]);
    Serial.print("    OFF ");
    Serial.println(lightningData.off[i]);
  }
}  // lightningShow


void OnDataRecv(const uint8_t *mac_addr, const uint8_t *incomingData, int len) {
  Serial.print("Packet received from: ");
  printMAC(mac_addr);
  Serial.println();
  Serial.print("data size = ");
  Serial.println(sizeof(incomingData));
  uint8_t type = incomingData[0];
  switch (type) {
    case LIGHTNING:  // we received lightning data from server
      memcpy(&lightningData, incomingData, sizeof(incomingData));
      Serial.println("LIGHTNING data packet received, starting lightningShow()");
      lightningShow();
      break;
  }
}

Receiver Serial Monitor:

23:51:32.865 -> LIGHTNING data packet received, starting lightningShow()
23:51:32.910 -> lightningShow()
23:51:32.910 -> lightningData.flashes = 3
23:51:32.910 -> Step 0:  ON 0    OFF 0
23:51:32.910 -> Step 1:  ON 0    OFF 0
23:51:32.910 -> Step 2:  ON 0    OFF 0

23:51:37.890 -> LIGHTNING data packet received, starting lightningShow()
23:51:37.890 -> lightningShow()
23:51:37.890 -> lightningData.flashes = 2
23:51:37.890 -> Step 0:  ON 0    OFF 0
23:51:37.890 -> Step 1:  ON 0    OFF 0

NOOOOOOOOOOOOOOOO!!!!!!!!!!! :face_exhaling:

Just checked on the data size... ESP-NOW maxes out at 250 bytes, and sizeof(lightningData) shows 26. Am I calculating this right?

I ran the transmit cycle a few times and got a size of 26 bytes each time...

Sending lightningData packet
lightningData.msgType = 2
lightningData.group = 97
lightningData.address = 197
lightningData.flashes = 2
Step 0:  ON 881    OFF 350
Step 1:  ON 378    OFF 407
sizeof(lightningData): 24

Sending lightningData packet
lightningData.msgType = 2
lightningData.group = 61
lightningData.address = 16
lightningData.flashes = 4
Step 0:  ON 853    OFF 321
Step 1:  ON 751    OFF 897
Step 2:  ON 707    OFF 467
Step 3:  ON 264    OFF 809
sizeof(lightningData): 24

Sending lightningData packet
lightningData.msgType = 2
lightningData.group = 247
lightningData.address = 146
lightningData.flashes = 3
Step 0:  ON 563    OFF 747
Step 1:  ON 226    OFF 734
Step 2:  ON 473    OFF 275
sizeof(lightningData): 24

I'm guessing this is because the struct defined the array size at maxFlashes, so the data packet size is the same if all 5 slots are populated or just 2.. :thinking:

sizeof(lightningData) is 24 (4 uint8_t and 10 uint16_t)
you always transmit/receive the whole structure even if you only assign 2 slots

upload the complete code of transmitter and receiver - fragments tend to miss critical parts

you could send just the part which contains data, e.g.

esp_now_send(NULL, (uint8_t *)&lightningData, sizeof(4+4*lightningData.flashes));

but get the code working first

without the receiver code it's hard to make any call

just in case, declare the structure as packed (no need for typedef)

struct __attribute__ ((packed)) struct_lightning {       // Define Lightning data type
  uint8_t msgType;       // this is a LIGHTNING packet, relay and sound effects later
  uint8_t group;         // The board's group ID (1 = lightning LEDs, 2 = relays, 3 = sound effects, etc)
  uint8_t address;       // The board's individual address (0 = broadcast)
  uint8_t flashes;       // The number of flashes in the sequence 1-maxFlash
  uint16_t on[maxFlashes];
  uint16_t off[maxFlashes];
};

the transmitter code of post #9 is not complete either, e.g. #includes and setup() are missing

Sorry to be so late in coming back to say thanks, been a #!&%@ time over the holidays. Nothing quite like a cast iron radiator shattering and spraying 195 degree water all over an 1896 Victorian mansion to make your Christmas Eve festive, right? :man_facepalming: At least there was no electrical damage. :roll_eyes:

Anway, I'm finally back at my computer working on this thing, and I got some great news... :smiley: ...the wireless LED control has been scrapped! FML. The client SOLD OFF the portrait frames that change from normal to macabre along with the lightning flashes (similar to this)... :rage:

There is some legitimately good news though - adding

__attribute__ ((packed))

to the struct definition seems to have fixed the issue (something I have seen very little documentation on and would NEVER have even known it was even a thing if it wasn't for your help). It's true, taking AP Comp Sci in high school using Pascal was really a waste of my time! (The year after I graduated they switched to C++!) :laughing:

I haven't had time to fully test it as other issues have taken up my attention, but the limited testing I did before Thanksgiving appeared to work and I am 99.999% this is the final fix for the wireless data issue. :partying_face:

I will be deploying this code in a new project for the aforementioned mansion for both environmental sensors (including water leak detection :face_with_spiral_eyes:) and controlling window LED strips (the owner liked the Christmas setup I did with theater stage lights and soon there will be permanent RGBW LED strips at the base of each window to do the same for holiday theming - :shamrock: :rabbit2: :christmas_tree: :gift_heart: :fireworks: etc. ).

So thank you to @horace and @J-M-L for helping me through this "big idea on tiny hardware"... I'd still be rewriting code tonight if it weren't for all of your help. :grin:

It’s a good language for learning algorithms and structured programming.

Knowing a language in itself is not the goal, it’s about the concepts you learn and can apply throughout your career (if you are making this your job).

So don’t regret spending time with Pascal and keep enriching your skills

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.